diff options
-rw-r--r-- | include/net/bluetooth/a2mp.h | 3 | ||||
-rw-r--r-- | include/net/bluetooth/amp.h | 2 | ||||
-rw-r--r-- | include/net/bluetooth/l2cap.h | 2 | ||||
-rw-r--r-- | net/bluetooth/a2mp.c | 41 | ||||
-rw-r--r-- | net/bluetooth/amp.c | 15 | ||||
-rw-r--r-- | net/bluetooth/hci_event.c | 21 |
6 files changed, 83 insertions, 1 deletions
diff --git a/include/net/bluetooth/a2mp.h b/include/net/bluetooth/a2mp.h index 9fda7c94913f..e776ab2dc572 100644 --- a/include/net/bluetooth/a2mp.h +++ b/include/net/bluetooth/a2mp.h | |||
@@ -22,6 +22,7 @@ | |||
22 | enum amp_mgr_state { | 22 | enum amp_mgr_state { |
23 | READ_LOC_AMP_INFO, | 23 | READ_LOC_AMP_INFO, |
24 | READ_LOC_AMP_ASSOC, | 24 | READ_LOC_AMP_ASSOC, |
25 | READ_LOC_AMP_ASSOC_FINAL, | ||
25 | }; | 26 | }; |
26 | 27 | ||
27 | struct amp_mgr { | 28 | struct amp_mgr { |
@@ -134,6 +135,7 @@ extern struct mutex amp_mgr_list_lock; | |||
134 | 135 | ||
135 | void amp_mgr_get(struct amp_mgr *mgr); | 136 | void amp_mgr_get(struct amp_mgr *mgr); |
136 | int amp_mgr_put(struct amp_mgr *mgr); | 137 | int amp_mgr_put(struct amp_mgr *mgr); |
138 | u8 __next_ident(struct amp_mgr *mgr); | ||
137 | struct l2cap_chan *a2mp_channel_create(struct l2cap_conn *conn, | 139 | struct l2cap_chan *a2mp_channel_create(struct l2cap_conn *conn, |
138 | struct sk_buff *skb); | 140 | struct sk_buff *skb); |
139 | struct amp_mgr *amp_mgr_lookup_by_state(u8 state); | 141 | struct amp_mgr *amp_mgr_lookup_by_state(u8 state); |
@@ -141,5 +143,6 @@ void a2mp_send(struct amp_mgr *mgr, u8 code, u8 ident, u16 len, void *data); | |||
141 | void a2mp_discover_amp(struct l2cap_chan *chan); | 143 | void a2mp_discover_amp(struct l2cap_chan *chan); |
142 | void a2mp_send_getinfo_rsp(struct hci_dev *hdev); | 144 | void a2mp_send_getinfo_rsp(struct hci_dev *hdev); |
143 | void a2mp_send_getampassoc_rsp(struct hci_dev *hdev, u8 status); | 145 | void a2mp_send_getampassoc_rsp(struct hci_dev *hdev, u8 status); |
146 | void a2mp_send_create_phy_link_req(struct hci_dev *hdev, u8 status); | ||
144 | 147 | ||
145 | #endif /* __A2MP_H */ | 148 | #endif /* __A2MP_H */ |
diff --git a/include/net/bluetooth/amp.h b/include/net/bluetooth/amp.h index 8f8032965eaf..70496c07afaa 100644 --- a/include/net/bluetooth/amp.h +++ b/include/net/bluetooth/amp.h | |||
@@ -37,6 +37,8 @@ int phylink_gen_key(struct hci_conn *hcon, u8 *data, u8 *len, u8 *type); | |||
37 | void amp_read_loc_info(struct hci_dev *hdev, struct amp_mgr *mgr); | 37 | void amp_read_loc_info(struct hci_dev *hdev, struct amp_mgr *mgr); |
38 | void amp_read_loc_assoc_frag(struct hci_dev *hdev, u8 phy_handle); | 38 | void amp_read_loc_assoc_frag(struct hci_dev *hdev, u8 phy_handle); |
39 | void amp_read_loc_assoc(struct hci_dev *hdev, struct amp_mgr *mgr); | 39 | void amp_read_loc_assoc(struct hci_dev *hdev, struct amp_mgr *mgr); |
40 | void amp_read_loc_assoc_final_data(struct hci_dev *hdev, | ||
41 | struct hci_conn *hcon); | ||
40 | void amp_create_phylink(struct hci_dev *hdev, struct amp_mgr *mgr, | 42 | void amp_create_phylink(struct hci_dev *hdev, struct amp_mgr *mgr, |
41 | struct hci_conn *hcon); | 43 | struct hci_conn *hcon); |
42 | void amp_write_remote_assoc(struct hci_dev *hdev, u8 handle); | 44 | void amp_write_remote_assoc(struct hci_dev *hdev, u8 handle); |
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 0967f9e33750..ab58b81fb7c5 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h | |||
@@ -508,6 +508,8 @@ struct l2cap_chan { | |||
508 | __u32 remote_acc_lat; | 508 | __u32 remote_acc_lat; |
509 | __u32 remote_flush_to; | 509 | __u32 remote_flush_to; |
510 | 510 | ||
511 | __u8 ctrl_id; | ||
512 | |||
511 | struct delayed_work chan_timer; | 513 | struct delayed_work chan_timer; |
512 | struct delayed_work retrans_timer; | 514 | struct delayed_work retrans_timer; |
513 | struct delayed_work monitor_timer; | 515 | struct delayed_work monitor_timer; |
diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c index 28d1246958be..375a67f501d0 100644 --- a/net/bluetooth/a2mp.c +++ b/net/bluetooth/a2mp.c | |||
@@ -67,7 +67,7 @@ void a2mp_send(struct amp_mgr *mgr, u8 code, u8 ident, u16 len, void *data) | |||
67 | kfree(cmd); | 67 | kfree(cmd); |
68 | } | 68 | } |
69 | 69 | ||
70 | static u8 __next_ident(struct amp_mgr *mgr) | 70 | u8 __next_ident(struct amp_mgr *mgr) |
71 | { | 71 | { |
72 | if (++mgr->ident == 0) | 72 | if (++mgr->ident == 0) |
73 | mgr->ident = 1; | 73 | mgr->ident = 1; |
@@ -420,6 +420,8 @@ static int a2mp_getampassoc_rsp(struct amp_mgr *mgr, struct sk_buff *skb, | |||
420 | 420 | ||
421 | BT_DBG("Created hcon %p: loc:%d -> rem:%d", hcon, hdev->id, rsp->id); | 421 | BT_DBG("Created hcon %p: loc:%d -> rem:%d", hcon, hdev->id, rsp->id); |
422 | 422 | ||
423 | mgr->bredr_chan->ctrl_id = rsp->id; | ||
424 | |||
423 | amp_create_phylink(hdev, mgr, hcon); | 425 | amp_create_phylink(hdev, mgr, hcon); |
424 | 426 | ||
425 | done: | 427 | done: |
@@ -876,6 +878,43 @@ void a2mp_send_getampassoc_rsp(struct hci_dev *hdev, u8 status) | |||
876 | kfree(rsp); | 878 | kfree(rsp); |
877 | } | 879 | } |
878 | 880 | ||
881 | void a2mp_send_create_phy_link_req(struct hci_dev *hdev, u8 status) | ||
882 | { | ||
883 | struct amp_mgr *mgr; | ||
884 | struct amp_assoc *loc_assoc = &hdev->loc_assoc; | ||
885 | struct a2mp_physlink_req *req; | ||
886 | struct l2cap_chan *bredr_chan; | ||
887 | size_t len; | ||
888 | |||
889 | mgr = amp_mgr_lookup_by_state(READ_LOC_AMP_ASSOC_FINAL); | ||
890 | if (!mgr) | ||
891 | return; | ||
892 | |||
893 | len = sizeof(*req) + loc_assoc->len; | ||
894 | |||
895 | BT_DBG("%s mgr %p assoc_len %zu", hdev->name, mgr, len); | ||
896 | |||
897 | req = kzalloc(len, GFP_KERNEL); | ||
898 | if (!req) { | ||
899 | amp_mgr_put(mgr); | ||
900 | return; | ||
901 | } | ||
902 | |||
903 | bredr_chan = mgr->bredr_chan; | ||
904 | if (!bredr_chan) | ||
905 | goto clean; | ||
906 | |||
907 | req->local_id = hdev->id; | ||
908 | req->remote_id = bredr_chan->ctrl_id; | ||
909 | memcpy(req->amp_assoc, loc_assoc->data, loc_assoc->len); | ||
910 | |||
911 | a2mp_send(mgr, A2MP_CREATEPHYSLINK_REQ, __next_ident(mgr), len, req); | ||
912 | |||
913 | clean: | ||
914 | amp_mgr_put(mgr); | ||
915 | kfree(req); | ||
916 | } | ||
917 | |||
879 | void a2mp_discover_amp(struct l2cap_chan *chan) | 918 | void a2mp_discover_amp(struct l2cap_chan *chan) |
880 | { | 919 | { |
881 | struct l2cap_conn *conn = chan->conn; | 920 | struct l2cap_conn *conn = chan->conn; |
diff --git a/net/bluetooth/amp.c b/net/bluetooth/amp.c index 5895ad0d2ac9..4f7b2647d5e9 100644 --- a/net/bluetooth/amp.c +++ b/net/bluetooth/amp.c | |||
@@ -233,6 +233,21 @@ void amp_read_loc_assoc(struct hci_dev *hdev, struct amp_mgr *mgr) | |||
233 | hci_send_cmd(hdev, HCI_OP_READ_LOCAL_AMP_ASSOC, sizeof(cp), &cp); | 233 | hci_send_cmd(hdev, HCI_OP_READ_LOCAL_AMP_ASSOC, sizeof(cp), &cp); |
234 | } | 234 | } |
235 | 235 | ||
236 | void amp_read_loc_assoc_final_data(struct hci_dev *hdev, | ||
237 | struct hci_conn *hcon) | ||
238 | { | ||
239 | struct hci_cp_read_local_amp_assoc cp; | ||
240 | struct amp_mgr *mgr = hcon->amp_mgr; | ||
241 | |||
242 | cp.phy_handle = hcon->handle; | ||
243 | cp.len_so_far = cpu_to_le16(0); | ||
244 | cp.max_len = cpu_to_le16(hdev->amp_assoc_size); | ||
245 | |||
246 | mgr->state = READ_LOC_AMP_ASSOC_FINAL; | ||
247 | |||
248 | /* Read Local AMP Assoc final link information data */ | ||
249 | hci_send_cmd(hdev, HCI_OP_READ_LOCAL_AMP_ASSOC, sizeof(cp), &cp); | ||
250 | } | ||
236 | 251 | ||
237 | /* Write AMP Assoc data fragments, returns true with last fragment written*/ | 252 | /* Write AMP Assoc data fragments, returns true with last fragment written*/ |
238 | static bool amp_write_rem_assoc_frag(struct hci_dev *hdev, | 253 | static bool amp_write_rem_assoc_frag(struct hci_dev *hdev, |
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 0b7ba1e39d45..d702ba1c171c 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c | |||
@@ -901,6 +901,7 @@ static void hci_cc_read_local_amp_assoc(struct hci_dev *hdev, | |||
901 | a2mp_rsp: | 901 | a2mp_rsp: |
902 | /* Send A2MP Rsp when all fragments are received */ | 902 | /* Send A2MP Rsp when all fragments are received */ |
903 | a2mp_send_getampassoc_rsp(hdev, rp->status); | 903 | a2mp_send_getampassoc_rsp(hdev, rp->status); |
904 | a2mp_send_create_phy_link_req(hdev, rp->status); | ||
904 | } | 905 | } |
905 | 906 | ||
906 | static void hci_cc_delete_stored_link_key(struct hci_dev *hdev, | 907 | static void hci_cc_delete_stored_link_key(struct hci_dev *hdev, |
@@ -3641,6 +3642,22 @@ static void hci_le_meta_evt(struct hci_dev *hdev, struct sk_buff *skb) | |||
3641 | } | 3642 | } |
3642 | } | 3643 | } |
3643 | 3644 | ||
3645 | static void hci_chan_selected_evt(struct hci_dev *hdev, struct sk_buff *skb) | ||
3646 | { | ||
3647 | struct hci_ev_channel_selected *ev = (void *) skb->data; | ||
3648 | struct hci_conn *hcon; | ||
3649 | |||
3650 | BT_DBG("%s handle 0x%2.2x", hdev->name, ev->phy_handle); | ||
3651 | |||
3652 | skb_pull(skb, sizeof(*ev)); | ||
3653 | |||
3654 | hcon = hci_conn_hash_lookup_handle(hdev, ev->phy_handle); | ||
3655 | if (!hcon) | ||
3656 | return; | ||
3657 | |||
3658 | amp_read_loc_assoc_final_data(hdev, hcon); | ||
3659 | } | ||
3660 | |||
3644 | void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb) | 3661 | void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb) |
3645 | { | 3662 | { |
3646 | struct hci_event_hdr *hdr = (void *) skb->data; | 3663 | struct hci_event_hdr *hdr = (void *) skb->data; |
@@ -3805,6 +3822,10 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb) | |||
3805 | hci_le_meta_evt(hdev, skb); | 3822 | hci_le_meta_evt(hdev, skb); |
3806 | break; | 3823 | break; |
3807 | 3824 | ||
3825 | case HCI_EV_CHANNEL_SELECTED: | ||
3826 | hci_chan_selected_evt(hdev, skb); | ||
3827 | break; | ||
3828 | |||
3808 | case HCI_EV_REMOTE_OOB_DATA_REQUEST: | 3829 | case HCI_EV_REMOTE_OOB_DATA_REQUEST: |
3809 | hci_remote_oob_data_request_evt(hdev, skb); | 3830 | hci_remote_oob_data_request_evt(hdev, skb); |
3810 | break; | 3831 | break; |