diff options
author | Andrei Emeltchenko <andrei.emeltchenko@intel.com> | 2012-09-27 10:26:10 -0400 |
---|---|---|
committer | Gustavo Padovan <gustavo.padovan@collabora.co.uk> | 2012-09-27 16:11:12 -0400 |
commit | aa09537d80bf7e6282103618eb496f03e76f2953 (patch) | |
tree | c1b4022bf6f70784fcc39f75b6a93bbda6dedb06 /net | |
parent | 903e45411099ae8292f5ce637ad0c72f6fef61db (diff) |
Bluetooth: A2MP: Process Discover Response
When receiving A2MP Discover Response send A2MP Get Info Request
for each AMP controller in the discovery list.
Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
Signed-off-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
Diffstat (limited to 'net')
-rw-r--r-- | net/bluetooth/a2mp.c | 62 |
1 files changed, 61 insertions, 1 deletions
diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c index 71400612843d..f04c44146663 100644 --- a/net/bluetooth/a2mp.c +++ b/net/bluetooth/a2mp.c | |||
@@ -67,6 +67,14 @@ 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) | ||
71 | { | ||
72 | if (++mgr->ident == 0) | ||
73 | mgr->ident = 1; | ||
74 | |||
75 | return mgr->ident; | ||
76 | } | ||
77 | |||
70 | static inline void __a2mp_cl_bredr(struct a2mp_cl *cl) | 78 | static inline void __a2mp_cl_bredr(struct a2mp_cl *cl) |
71 | { | 79 | { |
72 | cl->id = 0; | 80 | cl->id = 0; |
@@ -165,6 +173,55 @@ static int a2mp_discover_req(struct amp_mgr *mgr, struct sk_buff *skb, | |||
165 | return 0; | 173 | return 0; |
166 | } | 174 | } |
167 | 175 | ||
176 | static int a2mp_discover_rsp(struct amp_mgr *mgr, struct sk_buff *skb, | ||
177 | struct a2mp_cmd *hdr) | ||
178 | { | ||
179 | struct a2mp_discov_rsp *rsp = (void *) skb->data; | ||
180 | u16 len = le16_to_cpu(hdr->len); | ||
181 | struct a2mp_cl *cl; | ||
182 | u16 ext_feat; | ||
183 | |||
184 | if (len < sizeof(*rsp)) | ||
185 | return -EINVAL; | ||
186 | |||
187 | len -= sizeof(*rsp); | ||
188 | skb_pull(skb, sizeof(*rsp)); | ||
189 | |||
190 | ext_feat = le16_to_cpu(rsp->ext_feat); | ||
191 | |||
192 | BT_DBG("mtu %d efm 0x%4.4x", le16_to_cpu(rsp->mtu), ext_feat); | ||
193 | |||
194 | /* check that packet is not broken for now */ | ||
195 | while (ext_feat & A2MP_FEAT_EXT) { | ||
196 | if (len < sizeof(ext_feat)) | ||
197 | return -EINVAL; | ||
198 | |||
199 | ext_feat = get_unaligned_le16(skb->data); | ||
200 | BT_DBG("efm 0x%4.4x", ext_feat); | ||
201 | len -= sizeof(ext_feat); | ||
202 | skb_pull(skb, sizeof(ext_feat)); | ||
203 | } | ||
204 | |||
205 | cl = (void *) skb->data; | ||
206 | while (len >= sizeof(*cl)) { | ||
207 | BT_DBG("Remote AMP id %d type %d status %d", cl->id, cl->type, | ||
208 | cl->status); | ||
209 | |||
210 | if (cl->id != HCI_BREDR_ID && cl->type == HCI_AMP) { | ||
211 | struct a2mp_info_req req; | ||
212 | |||
213 | req.id = cl->id; | ||
214 | a2mp_send(mgr, A2MP_GETINFO_REQ, __next_ident(mgr), | ||
215 | sizeof(req), &req); | ||
216 | } | ||
217 | |||
218 | len -= sizeof(*cl); | ||
219 | cl = (void *) skb_pull(skb, sizeof(*cl)); | ||
220 | } | ||
221 | |||
222 | return 0; | ||
223 | } | ||
224 | |||
168 | static int a2mp_change_notify(struct amp_mgr *mgr, struct sk_buff *skb, | 225 | static int a2mp_change_notify(struct amp_mgr *mgr, struct sk_buff *skb, |
169 | struct a2mp_cmd *hdr) | 226 | struct a2mp_cmd *hdr) |
170 | { | 227 | { |
@@ -391,8 +448,11 @@ static int a2mp_chan_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb) | |||
391 | err = a2mp_discphyslink_req(mgr, skb, hdr); | 448 | err = a2mp_discphyslink_req(mgr, skb, hdr); |
392 | break; | 449 | break; |
393 | 450 | ||
394 | case A2MP_CHANGE_RSP: | ||
395 | case A2MP_DISCOVER_RSP: | 451 | case A2MP_DISCOVER_RSP: |
452 | err = a2mp_discover_rsp(mgr, skb, hdr); | ||
453 | break; | ||
454 | |||
455 | case A2MP_CHANGE_RSP: | ||
396 | case A2MP_GETINFO_RSP: | 456 | case A2MP_GETINFO_RSP: |
397 | case A2MP_GETAMPASSOC_RSP: | 457 | case A2MP_GETAMPASSOC_RSP: |
398 | case A2MP_CREATEPHYSLINK_RSP: | 458 | case A2MP_CREATEPHYSLINK_RSP: |