diff options
Diffstat (limited to 'net/bluetooth/a2mp.c')
-rw-r--r-- | net/bluetooth/a2mp.c | 72 |
1 files changed, 41 insertions, 31 deletions
diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c index 17f33a62f6db..efcd108822c4 100644 --- a/net/bluetooth/a2mp.c +++ b/net/bluetooth/a2mp.c | |||
@@ -15,8 +15,9 @@ | |||
15 | #include <net/bluetooth/bluetooth.h> | 15 | #include <net/bluetooth/bluetooth.h> |
16 | #include <net/bluetooth/hci_core.h> | 16 | #include <net/bluetooth/hci_core.h> |
17 | #include <net/bluetooth/l2cap.h> | 17 | #include <net/bluetooth/l2cap.h> |
18 | #include <net/bluetooth/a2mp.h> | 18 | |
19 | #include <net/bluetooth/amp.h> | 19 | #include "a2mp.h" |
20 | #include "amp.h" | ||
20 | 21 | ||
21 | /* Global AMP Manager list */ | 22 | /* Global AMP Manager list */ |
22 | LIST_HEAD(amp_mgr_list); | 23 | LIST_HEAD(amp_mgr_list); |
@@ -75,33 +76,26 @@ u8 __next_ident(struct amp_mgr *mgr) | |||
75 | return mgr->ident; | 76 | return mgr->ident; |
76 | } | 77 | } |
77 | 78 | ||
78 | static inline void __a2mp_cl_bredr(struct a2mp_cl *cl) | ||
79 | { | ||
80 | cl->id = 0; | ||
81 | cl->type = 0; | ||
82 | cl->status = 1; | ||
83 | } | ||
84 | |||
85 | /* hci_dev_list shall be locked */ | 79 | /* hci_dev_list shall be locked */ |
86 | static void __a2mp_add_cl(struct amp_mgr *mgr, struct a2mp_cl *cl, u8 num_ctrl) | 80 | static void __a2mp_add_cl(struct amp_mgr *mgr, struct a2mp_cl *cl) |
87 | { | 81 | { |
88 | int i = 0; | ||
89 | struct hci_dev *hdev; | 82 | struct hci_dev *hdev; |
83 | int i = 1; | ||
90 | 84 | ||
91 | __a2mp_cl_bredr(cl); | 85 | cl[0].id = AMP_ID_BREDR; |
86 | cl[0].type = AMP_TYPE_BREDR; | ||
87 | cl[0].status = AMP_STATUS_BLUETOOTH_ONLY; | ||
92 | 88 | ||
93 | list_for_each_entry(hdev, &hci_dev_list, list) { | 89 | list_for_each_entry(hdev, &hci_dev_list, list) { |
94 | /* Iterate through AMP controllers */ | 90 | if (hdev->dev_type == HCI_AMP) { |
95 | if (hdev->id == HCI_BREDR_ID) | 91 | cl[i].id = hdev->id; |
96 | continue; | 92 | cl[i].type = hdev->amp_type; |
97 | 93 | if (test_bit(HCI_UP, &hdev->flags)) | |
98 | /* Starting from second entry */ | 94 | cl[i].status = hdev->amp_status; |
99 | if (++i >= num_ctrl) | 95 | else |
100 | return; | 96 | cl[i].status = AMP_STATUS_POWERED_DOWN; |
101 | 97 | i++; | |
102 | cl[i].id = hdev->id; | 98 | } |
103 | cl[i].type = hdev->amp_type; | ||
104 | cl[i].status = hdev->amp_status; | ||
105 | } | 99 | } |
106 | } | 100 | } |
107 | 101 | ||
@@ -129,6 +123,7 @@ static int a2mp_discover_req(struct amp_mgr *mgr, struct sk_buff *skb, | |||
129 | struct a2mp_discov_rsp *rsp; | 123 | struct a2mp_discov_rsp *rsp; |
130 | u16 ext_feat; | 124 | u16 ext_feat; |
131 | u8 num_ctrl; | 125 | u8 num_ctrl; |
126 | struct hci_dev *hdev; | ||
132 | 127 | ||
133 | if (len < sizeof(*req)) | 128 | if (len < sizeof(*req)) |
134 | return -EINVAL; | 129 | return -EINVAL; |
@@ -152,7 +147,14 @@ static int a2mp_discover_req(struct amp_mgr *mgr, struct sk_buff *skb, | |||
152 | 147 | ||
153 | read_lock(&hci_dev_list_lock); | 148 | read_lock(&hci_dev_list_lock); |
154 | 149 | ||
155 | num_ctrl = __hci_num_ctrl(); | 150 | /* at minimum the BR/EDR needs to be listed */ |
151 | num_ctrl = 1; | ||
152 | |||
153 | list_for_each_entry(hdev, &hci_dev_list, list) { | ||
154 | if (hdev->dev_type == HCI_AMP) | ||
155 | num_ctrl++; | ||
156 | } | ||
157 | |||
156 | len = num_ctrl * sizeof(struct a2mp_cl) + sizeof(*rsp); | 158 | len = num_ctrl * sizeof(struct a2mp_cl) + sizeof(*rsp); |
157 | rsp = kmalloc(len, GFP_ATOMIC); | 159 | rsp = kmalloc(len, GFP_ATOMIC); |
158 | if (!rsp) { | 160 | if (!rsp) { |
@@ -163,7 +165,7 @@ static int a2mp_discover_req(struct amp_mgr *mgr, struct sk_buff *skb, | |||
163 | rsp->mtu = __constant_cpu_to_le16(L2CAP_A2MP_DEFAULT_MTU); | 165 | rsp->mtu = __constant_cpu_to_le16(L2CAP_A2MP_DEFAULT_MTU); |
164 | rsp->ext_feat = 0; | 166 | rsp->ext_feat = 0; |
165 | 167 | ||
166 | __a2mp_add_cl(mgr, rsp->cl, num_ctrl); | 168 | __a2mp_add_cl(mgr, rsp->cl); |
167 | 169 | ||
168 | read_unlock(&hci_dev_list_lock); | 170 | read_unlock(&hci_dev_list_lock); |
169 | 171 | ||
@@ -208,7 +210,7 @@ static int a2mp_discover_rsp(struct amp_mgr *mgr, struct sk_buff *skb, | |||
208 | BT_DBG("Remote AMP id %d type %d status %d", cl->id, cl->type, | 210 | BT_DBG("Remote AMP id %d type %d status %d", cl->id, cl->type, |
209 | cl->status); | 211 | cl->status); |
210 | 212 | ||
211 | if (cl->id != HCI_BREDR_ID && cl->type == HCI_AMP) { | 213 | if (cl->id != AMP_ID_BREDR && cl->type != AMP_TYPE_BREDR) { |
212 | struct a2mp_info_req req; | 214 | struct a2mp_info_req req; |
213 | 215 | ||
214 | found = true; | 216 | found = true; |
@@ -344,7 +346,7 @@ static int a2mp_getampassoc_req(struct amp_mgr *mgr, struct sk_buff *skb, | |||
344 | tmp = amp_mgr_lookup_by_state(READ_LOC_AMP_ASSOC); | 346 | tmp = amp_mgr_lookup_by_state(READ_LOC_AMP_ASSOC); |
345 | 347 | ||
346 | hdev = hci_dev_get(req->id); | 348 | hdev = hci_dev_get(req->id); |
347 | if (!hdev || hdev->amp_type == HCI_BREDR || tmp) { | 349 | if (!hdev || hdev->amp_type == AMP_TYPE_BREDR || tmp) { |
348 | struct a2mp_amp_assoc_rsp rsp; | 350 | struct a2mp_amp_assoc_rsp rsp; |
349 | rsp.id = req->id; | 351 | rsp.id = req->id; |
350 | 352 | ||
@@ -451,7 +453,7 @@ static int a2mp_createphyslink_req(struct amp_mgr *mgr, struct sk_buff *skb, | |||
451 | rsp.remote_id = req->local_id; | 453 | rsp.remote_id = req->local_id; |
452 | 454 | ||
453 | hdev = hci_dev_get(req->remote_id); | 455 | hdev = hci_dev_get(req->remote_id); |
454 | if (!hdev || hdev->amp_type != HCI_AMP) { | 456 | if (!hdev || hdev->amp_type == AMP_TYPE_BREDR) { |
455 | rsp.status = A2MP_STATUS_INVALID_CTRL_ID; | 457 | rsp.status = A2MP_STATUS_INVALID_CTRL_ID; |
456 | goto send_rsp; | 458 | goto send_rsp; |
457 | } | 459 | } |
@@ -535,7 +537,8 @@ static int a2mp_discphyslink_req(struct amp_mgr *mgr, struct sk_buff *skb, | |||
535 | goto send_rsp; | 537 | goto send_rsp; |
536 | } | 538 | } |
537 | 539 | ||
538 | hcon = hci_conn_hash_lookup_ba(hdev, AMP_LINK, mgr->l2cap_conn->dst); | 540 | hcon = hci_conn_hash_lookup_ba(hdev, AMP_LINK, |
541 | &mgr->l2cap_conn->hcon->dst); | ||
539 | if (!hcon) { | 542 | if (!hcon) { |
540 | BT_ERR("No phys link exist"); | 543 | BT_ERR("No phys link exist"); |
541 | rsp.status = A2MP_STATUS_NO_PHYSICAL_LINK_EXISTS; | 544 | rsp.status = A2MP_STATUS_NO_PHYSICAL_LINK_EXISTS; |
@@ -669,7 +672,8 @@ static void a2mp_chan_close_cb(struct l2cap_chan *chan) | |||
669 | l2cap_chan_put(chan); | 672 | l2cap_chan_put(chan); |
670 | } | 673 | } |
671 | 674 | ||
672 | static void a2mp_chan_state_change_cb(struct l2cap_chan *chan, int state) | 675 | static void a2mp_chan_state_change_cb(struct l2cap_chan *chan, int state, |
676 | int err) | ||
673 | { | 677 | { |
674 | struct amp_mgr *mgr = chan->data; | 678 | struct amp_mgr *mgr = chan->data; |
675 | 679 | ||
@@ -706,6 +710,9 @@ static struct l2cap_ops a2mp_chan_ops = { | |||
706 | .teardown = l2cap_chan_no_teardown, | 710 | .teardown = l2cap_chan_no_teardown, |
707 | .ready = l2cap_chan_no_ready, | 711 | .ready = l2cap_chan_no_ready, |
708 | .defer = l2cap_chan_no_defer, | 712 | .defer = l2cap_chan_no_defer, |
713 | .resume = l2cap_chan_no_resume, | ||
714 | .set_shutdown = l2cap_chan_no_set_shutdown, | ||
715 | .get_sndtimeo = l2cap_chan_no_get_sndtimeo, | ||
709 | }; | 716 | }; |
710 | 717 | ||
711 | static struct l2cap_chan *a2mp_chan_open(struct l2cap_conn *conn, bool locked) | 718 | static struct l2cap_chan *a2mp_chan_open(struct l2cap_conn *conn, bool locked) |
@@ -829,6 +836,9 @@ struct l2cap_chan *a2mp_channel_create(struct l2cap_conn *conn, | |||
829 | { | 836 | { |
830 | struct amp_mgr *mgr; | 837 | struct amp_mgr *mgr; |
831 | 838 | ||
839 | if (conn->hcon->type != ACL_LINK) | ||
840 | return NULL; | ||
841 | |||
832 | mgr = amp_mgr_create(conn, false); | 842 | mgr = amp_mgr_create(conn, false); |
833 | if (!mgr) { | 843 | if (!mgr) { |
834 | BT_ERR("Could not create AMP manager"); | 844 | BT_ERR("Could not create AMP manager"); |
@@ -871,7 +881,7 @@ void a2mp_send_getinfo_rsp(struct hci_dev *hdev) | |||
871 | rsp.id = hdev->id; | 881 | rsp.id = hdev->id; |
872 | rsp.status = A2MP_STATUS_INVALID_CTRL_ID; | 882 | rsp.status = A2MP_STATUS_INVALID_CTRL_ID; |
873 | 883 | ||
874 | if (hdev->amp_type != HCI_BREDR) { | 884 | if (hdev->amp_type != AMP_TYPE_BREDR) { |
875 | rsp.status = 0; | 885 | rsp.status = 0; |
876 | rsp.total_bw = cpu_to_le32(hdev->amp_total_bw); | 886 | rsp.total_bw = cpu_to_le32(hdev->amp_total_bw); |
877 | rsp.max_bw = cpu_to_le32(hdev->amp_max_bw); | 887 | rsp.max_bw = cpu_to_le32(hdev->amp_max_bw); |