aboutsummaryrefslogtreecommitdiffstats
path: root/net/bluetooth
diff options
context:
space:
mode:
authorVille Tervo <ville.tervo@nokia.com>2011-02-10 20:38:47 -0500
committerGustavo F. Padovan <padovan@profusion.mobi>2011-02-16 14:32:45 -0500
commitfcd89c09a59a054fb986861e0862aa2fff7d7c40 (patch)
tree115d525a9789e974b0a118d9cc22b792370f40f7 /net/bluetooth
parent63185f64ef06464706b32c9a301f71f68cd93e52 (diff)
Bluetooth: Add LE connect support
Bluetooth V4.0 adds support for Low Energy (LE) connections. Specification introduces new set of hci commands to control LE connection. This patch adds logic to create, cancel and disconnect LE connections. Signed-off-by: Ville Tervo <ville.tervo@nokia.com> Acked-by: Marcel Holtmann <marcel@holtmann.org> Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
Diffstat (limited to 'net/bluetooth')
-rw-r--r--net/bluetooth/hci_conn.c51
-rw-r--r--net/bluetooth/hci_event.c93
2 files changed, 141 insertions, 3 deletions
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index 42dc39f25b72..d0c470c18f9d 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -45,6 +45,32 @@
45#include <net/bluetooth/bluetooth.h> 45#include <net/bluetooth/bluetooth.h>
46#include <net/bluetooth/hci_core.h> 46#include <net/bluetooth/hci_core.h>
47 47
48static void hci_le_connect(struct hci_conn *conn)
49{
50 struct hci_dev *hdev = conn->hdev;
51 struct hci_cp_le_create_conn cp;
52
53 conn->state = BT_CONNECT;
54 conn->out = 1;
55
56 memset(&cp, 0, sizeof(cp));
57 cp.scan_interval = cpu_to_le16(0x0004);
58 cp.scan_window = cpu_to_le16(0x0004);
59 bacpy(&cp.peer_addr, &conn->dst);
60 cp.conn_interval_min = cpu_to_le16(0x0008);
61 cp.conn_interval_max = cpu_to_le16(0x0100);
62 cp.supervision_timeout = cpu_to_le16(0x0064);
63 cp.min_ce_len = cpu_to_le16(0x0001);
64 cp.max_ce_len = cpu_to_le16(0x0001);
65
66 hci_send_cmd(hdev, HCI_OP_LE_CREATE_CONN, sizeof(cp), &cp);
67}
68
69static void hci_le_connect_cancel(struct hci_conn *conn)
70{
71 hci_send_cmd(conn->hdev, HCI_OP_LE_CREATE_CONN_CANCEL, 0, NULL);
72}
73
48void hci_acl_connect(struct hci_conn *conn) 74void hci_acl_connect(struct hci_conn *conn)
49{ 75{
50 struct hci_dev *hdev = conn->hdev; 76 struct hci_dev *hdev = conn->hdev;
@@ -193,8 +219,12 @@ static void hci_conn_timeout(unsigned long arg)
193 switch (conn->state) { 219 switch (conn->state) {
194 case BT_CONNECT: 220 case BT_CONNECT:
195 case BT_CONNECT2: 221 case BT_CONNECT2:
196 if (conn->type == ACL_LINK && conn->out) 222 if (conn->out) {
197 hci_acl_connect_cancel(conn); 223 if (conn->type == ACL_LINK)
224 hci_acl_connect_cancel(conn);
225 else if (conn->type == LE_LINK)
226 hci_le_connect_cancel(conn);
227 }
198 break; 228 break;
199 case BT_CONFIG: 229 case BT_CONFIG:
200 case BT_CONNECTED: 230 case BT_CONNECTED:
@@ -361,15 +391,30 @@ struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src)
361} 391}
362EXPORT_SYMBOL(hci_get_route); 392EXPORT_SYMBOL(hci_get_route);
363 393
364/* Create SCO or ACL connection. 394/* Create SCO, ACL or LE connection.
365 * Device _must_ be locked */ 395 * Device _must_ be locked */
366struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8 sec_level, __u8 auth_type) 396struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8 sec_level, __u8 auth_type)
367{ 397{
368 struct hci_conn *acl; 398 struct hci_conn *acl;
369 struct hci_conn *sco; 399 struct hci_conn *sco;
400 struct hci_conn *le;
370 401
371 BT_DBG("%s dst %s", hdev->name, batostr(dst)); 402 BT_DBG("%s dst %s", hdev->name, batostr(dst));
372 403
404 if (type == LE_LINK) {
405 le = hci_conn_hash_lookup_ba(hdev, LE_LINK, dst);
406 if (!le)
407 le = hci_conn_add(hdev, LE_LINK, dst);
408 if (!le)
409 return NULL;
410 if (le->state == BT_OPEN)
411 hci_le_connect(le);
412
413 hci_conn_hold(le);
414
415 return le;
416 }
417
373 acl = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst); 418 acl = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst);
374 if (!acl) { 419 if (!acl) {
375 acl = hci_conn_add(hdev, ACL_LINK, dst); 420 acl = hci_conn_add(hdev, ACL_LINK, dst);
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index cee46cbe7aeb..47c6e9316ce8 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -1107,6 +1107,43 @@ static void hci_cs_exit_sniff_mode(struct hci_dev *hdev, __u8 status)
1107 hci_dev_unlock(hdev); 1107 hci_dev_unlock(hdev);
1108} 1108}
1109 1109
1110static void hci_cs_le_create_conn(struct hci_dev *hdev, __u8 status)
1111{
1112 struct hci_cp_le_create_conn *cp;
1113 struct hci_conn *conn;
1114
1115 BT_DBG("%s status 0x%x", hdev->name, status);
1116
1117 cp = hci_sent_cmd_data(hdev, HCI_OP_LE_CREATE_CONN);
1118 if (!cp)
1119 return;
1120
1121 hci_dev_lock(hdev);
1122
1123 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->peer_addr);
1124
1125 BT_DBG("%s bdaddr %s conn %p", hdev->name, batostr(&cp->peer_addr),
1126 conn);
1127
1128 if (status) {
1129 if (conn && conn->state == BT_CONNECT) {
1130 conn->state = BT_CLOSED;
1131 hci_proto_connect_cfm(conn, status);
1132 hci_conn_del(conn);
1133 }
1134 } else {
1135 if (!conn) {
1136 conn = hci_conn_add(hdev, LE_LINK, &cp->peer_addr);
1137 if (conn)
1138 conn->out = 1;
1139 else
1140 BT_ERR("No memory for new connection");
1141 }
1142 }
1143
1144 hci_dev_unlock(hdev);
1145}
1146
1110static inline void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) 1147static inline void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
1111{ 1148{
1112 __u8 status = *((__u8 *) skb->data); 1149 __u8 status = *((__u8 *) skb->data);
@@ -1738,6 +1775,10 @@ static inline void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb)
1738 mgmt_disconnect_failed(hdev->id); 1775 mgmt_disconnect_failed(hdev->id);
1739 break; 1776 break;
1740 1777
1778 case HCI_OP_LE_CREATE_CONN:
1779 hci_cs_le_create_conn(hdev, ev->status);
1780 break;
1781
1741 default: 1782 default:
1742 BT_DBG("%s opcode 0x%x", hdev->name, opcode); 1783 BT_DBG("%s opcode 0x%x", hdev->name, opcode);
1743 break; 1784 break;
@@ -2321,6 +2362,54 @@ static inline void hci_remote_host_features_evt(struct hci_dev *hdev, struct sk_
2321 hci_dev_unlock(hdev); 2362 hci_dev_unlock(hdev);
2322} 2363}
2323 2364
2365static inline void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
2366{
2367 struct hci_ev_le_conn_complete *ev = (void *) skb->data;
2368 struct hci_conn *conn;
2369
2370 BT_DBG("%s status %d", hdev->name, ev->status);
2371
2372 hci_dev_lock(hdev);
2373
2374 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &ev->bdaddr);
2375 if (!conn)
2376 goto unlock;
2377
2378 if (ev->status) {
2379 hci_proto_connect_cfm(conn, ev->status);
2380 conn->state = BT_CLOSED;
2381 hci_conn_del(conn);
2382 goto unlock;
2383 }
2384
2385 conn->handle = __le16_to_cpu(ev->handle);
2386 conn->state = BT_CONNECTED;
2387
2388 hci_conn_hold_device(conn);
2389 hci_conn_add_sysfs(conn);
2390
2391 hci_proto_connect_cfm(conn, ev->status);
2392
2393unlock:
2394 hci_dev_unlock(hdev);
2395}
2396
2397static inline void hci_le_meta_evt(struct hci_dev *hdev, struct sk_buff *skb)
2398{
2399 struct hci_ev_le_meta *le_ev = (void *) skb->data;
2400
2401 skb_pull(skb, sizeof(*le_ev));
2402
2403 switch (le_ev->subevent) {
2404 case HCI_EV_LE_CONN_COMPLETE:
2405 hci_le_conn_complete_evt(hdev, skb);
2406 break;
2407
2408 default:
2409 break;
2410 }
2411}
2412
2324void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb) 2413void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
2325{ 2414{
2326 struct hci_event_hdr *hdr = (void *) skb->data; 2415 struct hci_event_hdr *hdr = (void *) skb->data;
@@ -2461,6 +2550,10 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
2461 hci_remote_host_features_evt(hdev, skb); 2550 hci_remote_host_features_evt(hdev, skb);
2462 break; 2551 break;
2463 2552
2553 case HCI_EV_LE_META:
2554 hci_le_meta_evt(hdev, skb);
2555 break;
2556
2464 default: 2557 default:
2465 BT_DBG("%s event 0x%x", hdev->name, event); 2558 BT_DBG("%s event 0x%x", hdev->name, event);
2466 break; 2559 break;