diff options
Diffstat (limited to 'net/bluetooth/hci_conn.c')
-rw-r--r-- | net/bluetooth/hci_conn.c | 76 |
1 files changed, 70 insertions, 6 deletions
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index b9196a44f759..25bfce0666eb 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c | |||
@@ -130,6 +130,20 @@ void hci_acl_disconn(struct hci_conn *conn, __u8 reason) | |||
130 | hci_send_cmd(conn->hdev, HCI_OP_DISCONNECT, sizeof(cp), &cp); | 130 | hci_send_cmd(conn->hdev, HCI_OP_DISCONNECT, sizeof(cp), &cp); |
131 | } | 131 | } |
132 | 132 | ||
133 | static void hci_amp_disconn(struct hci_conn *conn, __u8 reason) | ||
134 | { | ||
135 | struct hci_cp_disconn_phy_link cp; | ||
136 | |||
137 | BT_DBG("hcon %p", conn); | ||
138 | |||
139 | conn->state = BT_DISCONN; | ||
140 | |||
141 | cp.phy_handle = HCI_PHY_HANDLE(conn->handle); | ||
142 | cp.reason = reason; | ||
143 | hci_send_cmd(conn->hdev, HCI_OP_DISCONN_PHY_LINK, | ||
144 | sizeof(cp), &cp); | ||
145 | } | ||
146 | |||
133 | static void hci_add_sco(struct hci_conn *conn, __u16 handle) | 147 | static void hci_add_sco(struct hci_conn *conn, __u16 handle) |
134 | { | 148 | { |
135 | struct hci_dev *hdev = conn->hdev; | 149 | struct hci_dev *hdev = conn->hdev; |
@@ -230,11 +244,24 @@ void hci_sco_setup(struct hci_conn *conn, __u8 status) | |||
230 | } | 244 | } |
231 | } | 245 | } |
232 | 246 | ||
247 | static void hci_conn_disconnect(struct hci_conn *conn) | ||
248 | { | ||
249 | __u8 reason = hci_proto_disconn_ind(conn); | ||
250 | |||
251 | switch (conn->type) { | ||
252 | case ACL_LINK: | ||
253 | hci_acl_disconn(conn, reason); | ||
254 | break; | ||
255 | case AMP_LINK: | ||
256 | hci_amp_disconn(conn, reason); | ||
257 | break; | ||
258 | } | ||
259 | } | ||
260 | |||
233 | static void hci_conn_timeout(struct work_struct *work) | 261 | static void hci_conn_timeout(struct work_struct *work) |
234 | { | 262 | { |
235 | struct hci_conn *conn = container_of(work, struct hci_conn, | 263 | struct hci_conn *conn = container_of(work, struct hci_conn, |
236 | disc_work.work); | 264 | disc_work.work); |
237 | __u8 reason; | ||
238 | 265 | ||
239 | BT_DBG("hcon %p state %s", conn, state_to_string(conn->state)); | 266 | BT_DBG("hcon %p state %s", conn, state_to_string(conn->state)); |
240 | 267 | ||
@@ -253,8 +280,7 @@ static void hci_conn_timeout(struct work_struct *work) | |||
253 | break; | 280 | break; |
254 | case BT_CONFIG: | 281 | case BT_CONFIG: |
255 | case BT_CONNECTED: | 282 | case BT_CONNECTED: |
256 | reason = hci_proto_disconn_ind(conn); | 283 | hci_conn_disconnect(conn); |
257 | hci_acl_disconn(conn, reason); | ||
258 | break; | 284 | break; |
259 | default: | 285 | default: |
260 | conn->state = BT_CLOSED; | 286 | conn->state = BT_CLOSED; |
@@ -320,7 +346,7 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst) | |||
320 | { | 346 | { |
321 | struct hci_conn *conn; | 347 | struct hci_conn *conn; |
322 | 348 | ||
323 | BT_DBG("%s dst %s", hdev->name, batostr(dst)); | 349 | BT_DBG("%s dst %pMR", hdev->name, dst); |
324 | 350 | ||
325 | conn = kzalloc(sizeof(struct hci_conn), GFP_KERNEL); | 351 | conn = kzalloc(sizeof(struct hci_conn), GFP_KERNEL); |
326 | if (!conn) | 352 | if (!conn) |
@@ -437,7 +463,7 @@ struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src) | |||
437 | int use_src = bacmp(src, BDADDR_ANY); | 463 | int use_src = bacmp(src, BDADDR_ANY); |
438 | struct hci_dev *hdev = NULL, *d; | 464 | struct hci_dev *hdev = NULL, *d; |
439 | 465 | ||
440 | BT_DBG("%s -> %s", batostr(src), batostr(dst)); | 466 | BT_DBG("%pMR -> %pMR", src, dst); |
441 | 467 | ||
442 | read_lock(&hci_dev_list_lock); | 468 | read_lock(&hci_dev_list_lock); |
443 | 469 | ||
@@ -476,6 +502,9 @@ static struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst, | |||
476 | { | 502 | { |
477 | struct hci_conn *le; | 503 | struct hci_conn *le; |
478 | 504 | ||
505 | if (test_bit(HCI_LE_PERIPHERAL, &hdev->flags)) | ||
506 | return ERR_PTR(-ENOTSUPP); | ||
507 | |||
479 | le = hci_conn_hash_lookup_ba(hdev, LE_LINK, dst); | 508 | le = hci_conn_hash_lookup_ba(hdev, LE_LINK, dst); |
480 | if (!le) { | 509 | if (!le) { |
481 | le = hci_conn_hash_lookup_state(hdev, LE_LINK, BT_CONNECT); | 510 | le = hci_conn_hash_lookup_state(hdev, LE_LINK, BT_CONNECT); |
@@ -567,7 +596,7 @@ static struct hci_conn *hci_connect_sco(struct hci_dev *hdev, int type, | |||
567 | struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, | 596 | struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, |
568 | __u8 dst_type, __u8 sec_level, __u8 auth_type) | 597 | __u8 dst_type, __u8 sec_level, __u8 auth_type) |
569 | { | 598 | { |
570 | BT_DBG("%s dst %s type 0x%x", hdev->name, batostr(dst), type); | 599 | BT_DBG("%s dst %pMR type 0x%x", hdev->name, dst, type); |
571 | 600 | ||
572 | switch (type) { | 601 | switch (type) { |
573 | case LE_LINK: | 602 | case LE_LINK: |
@@ -933,6 +962,7 @@ struct hci_chan *hci_chan_create(struct hci_conn *conn) | |||
933 | 962 | ||
934 | chan->conn = conn; | 963 | chan->conn = conn; |
935 | skb_queue_head_init(&chan->data_q); | 964 | skb_queue_head_init(&chan->data_q); |
965 | chan->state = BT_CONNECTED; | ||
936 | 966 | ||
937 | list_add_rcu(&chan->list, &conn->chan_list); | 967 | list_add_rcu(&chan->list, &conn->chan_list); |
938 | 968 | ||
@@ -950,6 +980,8 @@ void hci_chan_del(struct hci_chan *chan) | |||
950 | 980 | ||
951 | synchronize_rcu(); | 981 | synchronize_rcu(); |
952 | 982 | ||
983 | hci_conn_put(conn); | ||
984 | |||
953 | skb_queue_purge(&chan->data_q); | 985 | skb_queue_purge(&chan->data_q); |
954 | kfree(chan); | 986 | kfree(chan); |
955 | } | 987 | } |
@@ -963,3 +995,35 @@ void hci_chan_list_flush(struct hci_conn *conn) | |||
963 | list_for_each_entry_safe(chan, n, &conn->chan_list, list) | 995 | list_for_each_entry_safe(chan, n, &conn->chan_list, list) |
964 | hci_chan_del(chan); | 996 | hci_chan_del(chan); |
965 | } | 997 | } |
998 | |||
999 | static struct hci_chan *__hci_chan_lookup_handle(struct hci_conn *hcon, | ||
1000 | __u16 handle) | ||
1001 | { | ||
1002 | struct hci_chan *hchan; | ||
1003 | |||
1004 | list_for_each_entry(hchan, &hcon->chan_list, list) { | ||
1005 | if (hchan->handle == handle) | ||
1006 | return hchan; | ||
1007 | } | ||
1008 | |||
1009 | return NULL; | ||
1010 | } | ||
1011 | |||
1012 | struct hci_chan *hci_chan_lookup_handle(struct hci_dev *hdev, __u16 handle) | ||
1013 | { | ||
1014 | struct hci_conn_hash *h = &hdev->conn_hash; | ||
1015 | struct hci_conn *hcon; | ||
1016 | struct hci_chan *hchan = NULL; | ||
1017 | |||
1018 | rcu_read_lock(); | ||
1019 | |||
1020 | list_for_each_entry_rcu(hcon, &h->list, list) { | ||
1021 | hchan = __hci_chan_lookup_handle(hcon, handle); | ||
1022 | if (hchan) | ||
1023 | break; | ||
1024 | } | ||
1025 | |||
1026 | rcu_read_unlock(); | ||
1027 | |||
1028 | return hchan; | ||
1029 | } | ||