diff options
Diffstat (limited to 'net/bluetooth/hci_conn.c')
-rw-r--r-- | net/bluetooth/hci_conn.c | 96 |
1 files changed, 76 insertions, 20 deletions
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index f8880261da0e..ca8d05245ca0 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c | |||
@@ -59,24 +59,31 @@ void hci_acl_connect(struct hci_conn *conn) | |||
59 | BT_DBG("%p", conn); | 59 | BT_DBG("%p", conn); |
60 | 60 | ||
61 | conn->state = BT_CONNECT; | 61 | conn->state = BT_CONNECT; |
62 | conn->out = 1; | 62 | conn->out = 1; |
63 | |||
63 | conn->link_mode = HCI_LM_MASTER; | 64 | conn->link_mode = HCI_LM_MASTER; |
64 | 65 | ||
65 | conn->attempt++; | 66 | conn->attempt++; |
66 | 67 | ||
68 | conn->link_policy = hdev->link_policy; | ||
69 | |||
67 | memset(&cp, 0, sizeof(cp)); | 70 | memset(&cp, 0, sizeof(cp)); |
68 | bacpy(&cp.bdaddr, &conn->dst); | 71 | bacpy(&cp.bdaddr, &conn->dst); |
69 | cp.pscan_rep_mode = 0x02; | 72 | cp.pscan_rep_mode = 0x02; |
70 | 73 | ||
71 | if ((ie = hci_inquiry_cache_lookup(hdev, &conn->dst)) && | 74 | if ((ie = hci_inquiry_cache_lookup(hdev, &conn->dst))) { |
72 | inquiry_entry_age(ie) <= INQUIRY_ENTRY_AGE_MAX) { | 75 | if (inquiry_entry_age(ie) <= INQUIRY_ENTRY_AGE_MAX) { |
73 | cp.pscan_rep_mode = ie->data.pscan_rep_mode; | 76 | cp.pscan_rep_mode = ie->data.pscan_rep_mode; |
74 | cp.pscan_mode = ie->data.pscan_mode; | 77 | cp.pscan_mode = ie->data.pscan_mode; |
75 | cp.clock_offset = ie->data.clock_offset | cpu_to_le16(0x8000); | 78 | cp.clock_offset = ie->data.clock_offset | |
79 | cpu_to_le16(0x8000); | ||
80 | } | ||
81 | |||
76 | memcpy(conn->dev_class, ie->data.dev_class, 3); | 82 | memcpy(conn->dev_class, ie->data.dev_class, 3); |
83 | conn->ssp_mode = ie->data.ssp_mode; | ||
77 | } | 84 | } |
78 | 85 | ||
79 | cp.pkt_type = cpu_to_le16(hdev->pkt_type & ACL_PTYPE_MASK); | 86 | cp.pkt_type = cpu_to_le16(conn->pkt_type); |
80 | if (lmp_rswitch_capable(hdev) && !(hdev->link_mode & HCI_LM_MASTER)) | 87 | if (lmp_rswitch_capable(hdev) && !(hdev->link_mode & HCI_LM_MASTER)) |
81 | cp.role_switch = 0x01; | 88 | cp.role_switch = 0x01; |
82 | else | 89 | else |
@@ -122,7 +129,7 @@ void hci_add_sco(struct hci_conn *conn, __u16 handle) | |||
122 | conn->out = 1; | 129 | conn->out = 1; |
123 | 130 | ||
124 | cp.handle = cpu_to_le16(handle); | 131 | cp.handle = cpu_to_le16(handle); |
125 | cp.pkt_type = cpu_to_le16(hdev->pkt_type & SCO_PTYPE_MASK); | 132 | cp.pkt_type = cpu_to_le16(conn->pkt_type); |
126 | 133 | ||
127 | hci_send_cmd(hdev, HCI_OP_ADD_SCO, sizeof(cp), &cp); | 134 | hci_send_cmd(hdev, HCI_OP_ADD_SCO, sizeof(cp), &cp); |
128 | } | 135 | } |
@@ -138,7 +145,7 @@ void hci_setup_sync(struct hci_conn *conn, __u16 handle) | |||
138 | conn->out = 1; | 145 | conn->out = 1; |
139 | 146 | ||
140 | cp.handle = cpu_to_le16(handle); | 147 | cp.handle = cpu_to_le16(handle); |
141 | cp.pkt_type = cpu_to_le16(hdev->esco_type); | 148 | cp.pkt_type = cpu_to_le16(conn->pkt_type); |
142 | 149 | ||
143 | cp.tx_bandwidth = cpu_to_le32(0x00001f40); | 150 | cp.tx_bandwidth = cpu_to_le32(0x00001f40); |
144 | cp.rx_bandwidth = cpu_to_le32(0x00001f40); | 151 | cp.rx_bandwidth = cpu_to_le32(0x00001f40); |
@@ -163,11 +170,13 @@ static void hci_conn_timeout(unsigned long arg) | |||
163 | 170 | ||
164 | switch (conn->state) { | 171 | switch (conn->state) { |
165 | case BT_CONNECT: | 172 | case BT_CONNECT: |
173 | case BT_CONNECT2: | ||
166 | if (conn->type == ACL_LINK) | 174 | if (conn->type == ACL_LINK) |
167 | hci_acl_connect_cancel(conn); | 175 | hci_acl_connect_cancel(conn); |
168 | else | 176 | else |
169 | hci_acl_disconn(conn, 0x13); | 177 | hci_acl_disconn(conn, 0x13); |
170 | break; | 178 | break; |
179 | case BT_CONFIG: | ||
171 | case BT_CONNECTED: | 180 | case BT_CONNECTED: |
172 | hci_acl_disconn(conn, 0x13); | 181 | hci_acl_disconn(conn, 0x13); |
173 | break; | 182 | break; |
@@ -199,13 +208,28 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst) | |||
199 | return NULL; | 208 | return NULL; |
200 | 209 | ||
201 | bacpy(&conn->dst, dst); | 210 | bacpy(&conn->dst, dst); |
202 | conn->hdev = hdev; | 211 | conn->hdev = hdev; |
203 | conn->type = type; | 212 | conn->type = type; |
204 | conn->mode = HCI_CM_ACTIVE; | 213 | conn->mode = HCI_CM_ACTIVE; |
205 | conn->state = BT_OPEN; | 214 | conn->state = BT_OPEN; |
206 | 215 | ||
207 | conn->power_save = 1; | 216 | conn->power_save = 1; |
208 | 217 | ||
218 | switch (type) { | ||
219 | case ACL_LINK: | ||
220 | conn->pkt_type = hdev->pkt_type & ACL_PTYPE_MASK; | ||
221 | break; | ||
222 | case SCO_LINK: | ||
223 | if (lmp_esco_capable(hdev)) | ||
224 | conn->pkt_type = hdev->esco_type & SCO_ESCO_MASK; | ||
225 | else | ||
226 | conn->pkt_type = hdev->pkt_type & SCO_PTYPE_MASK; | ||
227 | break; | ||
228 | case ESCO_LINK: | ||
229 | conn->pkt_type = hdev->esco_type; | ||
230 | break; | ||
231 | } | ||
232 | |||
209 | skb_queue_head_init(&conn->data_q); | 233 | skb_queue_head_init(&conn->data_q); |
210 | 234 | ||
211 | setup_timer(&conn->disc_timer, hci_conn_timeout, (unsigned long)conn); | 235 | setup_timer(&conn->disc_timer, hci_conn_timeout, (unsigned long)conn); |
@@ -221,8 +245,6 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst) | |||
221 | if (hdev->notify) | 245 | if (hdev->notify) |
222 | hdev->notify(hdev, HCI_NOTIFY_CONN_ADD); | 246 | hdev->notify(hdev, HCI_NOTIFY_CONN_ADD); |
223 | 247 | ||
224 | hci_conn_add_sysfs(conn); | ||
225 | |||
226 | tasklet_enable(&hdev->tx_task); | 248 | tasklet_enable(&hdev->tx_task); |
227 | 249 | ||
228 | return conn; | 250 | return conn; |
@@ -254,12 +276,14 @@ int hci_conn_del(struct hci_conn *conn) | |||
254 | } | 276 | } |
255 | 277 | ||
256 | tasklet_disable(&hdev->tx_task); | 278 | tasklet_disable(&hdev->tx_task); |
279 | |||
257 | hci_conn_hash_del(hdev, conn); | 280 | hci_conn_hash_del(hdev, conn); |
258 | if (hdev->notify) | 281 | if (hdev->notify) |
259 | hdev->notify(hdev, HCI_NOTIFY_CONN_DEL); | 282 | hdev->notify(hdev, HCI_NOTIFY_CONN_DEL); |
283 | |||
260 | tasklet_enable(&hdev->tx_task); | 284 | tasklet_enable(&hdev->tx_task); |
285 | |||
261 | skb_queue_purge(&conn->data_q); | 286 | skb_queue_purge(&conn->data_q); |
262 | hci_conn_del_sysfs(conn); | ||
263 | 287 | ||
264 | return 0; | 288 | return 0; |
265 | } | 289 | } |
@@ -355,13 +379,21 @@ int hci_conn_auth(struct hci_conn *conn) | |||
355 | { | 379 | { |
356 | BT_DBG("conn %p", conn); | 380 | BT_DBG("conn %p", conn); |
357 | 381 | ||
382 | if (conn->ssp_mode > 0 && conn->hdev->ssp_mode > 0) { | ||
383 | if (!(conn->auth_type & 0x01)) { | ||
384 | conn->auth_type = HCI_AT_GENERAL_BONDING_MITM; | ||
385 | conn->link_mode &= ~HCI_LM_AUTH; | ||
386 | } | ||
387 | } | ||
388 | |||
358 | if (conn->link_mode & HCI_LM_AUTH) | 389 | if (conn->link_mode & HCI_LM_AUTH) |
359 | return 1; | 390 | return 1; |
360 | 391 | ||
361 | if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) { | 392 | if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) { |
362 | struct hci_cp_auth_requested cp; | 393 | struct hci_cp_auth_requested cp; |
363 | cp.handle = cpu_to_le16(conn->handle); | 394 | cp.handle = cpu_to_le16(conn->handle); |
364 | hci_send_cmd(conn->hdev, HCI_OP_AUTH_REQUESTED, sizeof(cp), &cp); | 395 | hci_send_cmd(conn->hdev, HCI_OP_AUTH_REQUESTED, |
396 | sizeof(cp), &cp); | ||
365 | } | 397 | } |
366 | return 0; | 398 | return 0; |
367 | } | 399 | } |
@@ -373,7 +405,7 @@ int hci_conn_encrypt(struct hci_conn *conn) | |||
373 | BT_DBG("conn %p", conn); | 405 | BT_DBG("conn %p", conn); |
374 | 406 | ||
375 | if (conn->link_mode & HCI_LM_ENCRYPT) | 407 | if (conn->link_mode & HCI_LM_ENCRYPT) |
376 | return 1; | 408 | return hci_conn_auth(conn); |
377 | 409 | ||
378 | if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) | 410 | if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) |
379 | return 0; | 411 | return 0; |
@@ -382,7 +414,8 @@ int hci_conn_encrypt(struct hci_conn *conn) | |||
382 | struct hci_cp_set_conn_encrypt cp; | 414 | struct hci_cp_set_conn_encrypt cp; |
383 | cp.handle = cpu_to_le16(conn->handle); | 415 | cp.handle = cpu_to_le16(conn->handle); |
384 | cp.encrypt = 1; | 416 | cp.encrypt = 1; |
385 | hci_send_cmd(conn->hdev, HCI_OP_SET_CONN_ENCRYPT, sizeof(cp), &cp); | 417 | hci_send_cmd(conn->hdev, HCI_OP_SET_CONN_ENCRYPT, |
418 | sizeof(cp), &cp); | ||
386 | } | 419 | } |
387 | return 0; | 420 | return 0; |
388 | } | 421 | } |
@@ -396,7 +429,8 @@ int hci_conn_change_link_key(struct hci_conn *conn) | |||
396 | if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) { | 429 | if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) { |
397 | struct hci_cp_change_conn_link_key cp; | 430 | struct hci_cp_change_conn_link_key cp; |
398 | cp.handle = cpu_to_le16(conn->handle); | 431 | cp.handle = cpu_to_le16(conn->handle); |
399 | hci_send_cmd(conn->hdev, HCI_OP_CHANGE_CONN_LINK_KEY, sizeof(cp), &cp); | 432 | hci_send_cmd(conn->hdev, HCI_OP_CHANGE_CONN_LINK_KEY, |
433 | sizeof(cp), &cp); | ||
400 | } | 434 | } |
401 | return 0; | 435 | return 0; |
402 | } | 436 | } |
@@ -498,6 +532,8 @@ void hci_conn_hash_flush(struct hci_dev *hdev) | |||
498 | 532 | ||
499 | c->state = BT_CLOSED; | 533 | c->state = BT_CLOSED; |
500 | 534 | ||
535 | hci_conn_del_sysfs(c); | ||
536 | |||
501 | hci_proto_disconn_ind(c, 0x16); | 537 | hci_proto_disconn_ind(c, 0x16); |
502 | hci_conn_del(c); | 538 | hci_conn_del(c); |
503 | } | 539 | } |
@@ -600,3 +636,23 @@ int hci_get_conn_info(struct hci_dev *hdev, void __user *arg) | |||
600 | 636 | ||
601 | return copy_to_user(ptr, &ci, sizeof(ci)) ? -EFAULT : 0; | 637 | return copy_to_user(ptr, &ci, sizeof(ci)) ? -EFAULT : 0; |
602 | } | 638 | } |
639 | |||
640 | int hci_get_auth_info(struct hci_dev *hdev, void __user *arg) | ||
641 | { | ||
642 | struct hci_auth_info_req req; | ||
643 | struct hci_conn *conn; | ||
644 | |||
645 | if (copy_from_user(&req, arg, sizeof(req))) | ||
646 | return -EFAULT; | ||
647 | |||
648 | hci_dev_lock_bh(hdev); | ||
649 | conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &req.bdaddr); | ||
650 | if (conn) | ||
651 | req.type = conn->auth_type; | ||
652 | hci_dev_unlock_bh(hdev); | ||
653 | |||
654 | if (!conn) | ||
655 | return -ENOENT; | ||
656 | |||
657 | return copy_to_user(arg, &req, sizeof(req)) ? -EFAULT : 0; | ||
658 | } | ||