diff options
Diffstat (limited to 'net/bluetooth/hci_conn.c')
-rw-r--r-- | net/bluetooth/hci_conn.c | 78 |
1 files changed, 75 insertions, 3 deletions
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 99cd8d9d891b..a050a6984901 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c | |||
@@ -45,6 +45,33 @@ | |||
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 | ||
48 | static 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 | conn->link_mode |= HCI_LM_MASTER; | ||
56 | |||
57 | memset(&cp, 0, sizeof(cp)); | ||
58 | cp.scan_interval = cpu_to_le16(0x0004); | ||
59 | cp.scan_window = cpu_to_le16(0x0004); | ||
60 | bacpy(&cp.peer_addr, &conn->dst); | ||
61 | cp.conn_interval_min = cpu_to_le16(0x0008); | ||
62 | cp.conn_interval_max = cpu_to_le16(0x0100); | ||
63 | cp.supervision_timeout = cpu_to_le16(0x0064); | ||
64 | cp.min_ce_len = cpu_to_le16(0x0001); | ||
65 | cp.max_ce_len = cpu_to_le16(0x0001); | ||
66 | |||
67 | hci_send_cmd(hdev, HCI_OP_LE_CREATE_CONN, sizeof(cp), &cp); | ||
68 | } | ||
69 | |||
70 | static void hci_le_connect_cancel(struct hci_conn *conn) | ||
71 | { | ||
72 | hci_send_cmd(conn->hdev, HCI_OP_LE_CREATE_CONN_CANCEL, 0, NULL); | ||
73 | } | ||
74 | |||
48 | void hci_acl_connect(struct hci_conn *conn) | 75 | void hci_acl_connect(struct hci_conn *conn) |
49 | { | 76 | { |
50 | struct hci_dev *hdev = conn->hdev; | 77 | struct hci_dev *hdev = conn->hdev; |
@@ -156,6 +183,26 @@ void hci_setup_sync(struct hci_conn *conn, __u16 handle) | |||
156 | hci_send_cmd(hdev, HCI_OP_SETUP_SYNC_CONN, sizeof(cp), &cp); | 183 | hci_send_cmd(hdev, HCI_OP_SETUP_SYNC_CONN, sizeof(cp), &cp); |
157 | } | 184 | } |
158 | 185 | ||
186 | void hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max, | ||
187 | u16 latency, u16 to_multiplier) | ||
188 | { | ||
189 | struct hci_cp_le_conn_update cp; | ||
190 | struct hci_dev *hdev = conn->hdev; | ||
191 | |||
192 | memset(&cp, 0, sizeof(cp)); | ||
193 | |||
194 | cp.handle = cpu_to_le16(conn->handle); | ||
195 | cp.conn_interval_min = cpu_to_le16(min); | ||
196 | cp.conn_interval_max = cpu_to_le16(max); | ||
197 | cp.conn_latency = cpu_to_le16(latency); | ||
198 | cp.supervision_timeout = cpu_to_le16(to_multiplier); | ||
199 | cp.min_ce_len = cpu_to_le16(0x0001); | ||
200 | cp.max_ce_len = cpu_to_le16(0x0001); | ||
201 | |||
202 | hci_send_cmd(hdev, HCI_OP_LE_CONN_UPDATE, sizeof(cp), &cp); | ||
203 | } | ||
204 | EXPORT_SYMBOL(hci_le_conn_update); | ||
205 | |||
159 | /* Device _must_ be locked */ | 206 | /* Device _must_ be locked */ |
160 | void hci_sco_setup(struct hci_conn *conn, __u8 status) | 207 | void hci_sco_setup(struct hci_conn *conn, __u8 status) |
161 | { | 208 | { |
@@ -193,8 +240,12 @@ static void hci_conn_timeout(unsigned long arg) | |||
193 | switch (conn->state) { | 240 | switch (conn->state) { |
194 | case BT_CONNECT: | 241 | case BT_CONNECT: |
195 | case BT_CONNECT2: | 242 | case BT_CONNECT2: |
196 | if (conn->type == ACL_LINK && conn->out) | 243 | if (conn->out) { |
197 | hci_acl_connect_cancel(conn); | 244 | if (conn->type == ACL_LINK) |
245 | hci_acl_connect_cancel(conn); | ||
246 | else if (conn->type == LE_LINK) | ||
247 | hci_le_connect_cancel(conn); | ||
248 | } | ||
198 | break; | 249 | break; |
199 | case BT_CONFIG: | 250 | case BT_CONFIG: |
200 | case BT_CONNECTED: | 251 | case BT_CONNECTED: |
@@ -234,6 +285,7 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst) | |||
234 | conn->mode = HCI_CM_ACTIVE; | 285 | conn->mode = HCI_CM_ACTIVE; |
235 | conn->state = BT_OPEN; | 286 | conn->state = BT_OPEN; |
236 | conn->auth_type = HCI_AT_GENERAL_BONDING; | 287 | conn->auth_type = HCI_AT_GENERAL_BONDING; |
288 | conn->io_capability = hdev->io_capability; | ||
237 | 289 | ||
238 | conn->power_save = 1; | 290 | conn->power_save = 1; |
239 | conn->disc_timeout = HCI_DISCONN_TIMEOUT; | 291 | conn->disc_timeout = HCI_DISCONN_TIMEOUT; |
@@ -295,6 +347,11 @@ int hci_conn_del(struct hci_conn *conn) | |||
295 | 347 | ||
296 | /* Unacked frames */ | 348 | /* Unacked frames */ |
297 | hdev->acl_cnt += conn->sent; | 349 | hdev->acl_cnt += conn->sent; |
350 | } else if (conn->type == LE_LINK) { | ||
351 | if (hdev->le_pkts) | ||
352 | hdev->le_cnt += conn->sent; | ||
353 | else | ||
354 | hdev->acl_cnt += conn->sent; | ||
298 | } else { | 355 | } else { |
299 | struct hci_conn *acl = conn->link; | 356 | struct hci_conn *acl = conn->link; |
300 | if (acl) { | 357 | if (acl) { |
@@ -360,15 +417,30 @@ struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src) | |||
360 | } | 417 | } |
361 | EXPORT_SYMBOL(hci_get_route); | 418 | EXPORT_SYMBOL(hci_get_route); |
362 | 419 | ||
363 | /* Create SCO or ACL connection. | 420 | /* Create SCO, ACL or LE connection. |
364 | * Device _must_ be locked */ | 421 | * Device _must_ be locked */ |
365 | struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8 sec_level, __u8 auth_type) | 422 | struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8 sec_level, __u8 auth_type) |
366 | { | 423 | { |
367 | struct hci_conn *acl; | 424 | struct hci_conn *acl; |
368 | struct hci_conn *sco; | 425 | struct hci_conn *sco; |
426 | struct hci_conn *le; | ||
369 | 427 | ||
370 | BT_DBG("%s dst %s", hdev->name, batostr(dst)); | 428 | BT_DBG("%s dst %s", hdev->name, batostr(dst)); |
371 | 429 | ||
430 | if (type == LE_LINK) { | ||
431 | le = hci_conn_hash_lookup_ba(hdev, LE_LINK, dst); | ||
432 | if (!le) | ||
433 | le = hci_conn_add(hdev, LE_LINK, dst); | ||
434 | if (!le) | ||
435 | return NULL; | ||
436 | if (le->state == BT_OPEN) | ||
437 | hci_le_connect(le); | ||
438 | |||
439 | hci_conn_hold(le); | ||
440 | |||
441 | return le; | ||
442 | } | ||
443 | |||
372 | acl = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst); | 444 | acl = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst); |
373 | if (!acl) { | 445 | if (!acl) { |
374 | acl = hci_conn_add(hdev, ACL_LINK, dst); | 446 | acl = hci_conn_add(hdev, ACL_LINK, dst); |