diff options
author | Andrei Emeltchenko <andrei.emeltchenko@intel.com> | 2012-09-27 10:26:15 -0400 |
---|---|---|
committer | Gustavo Padovan <gustavo.padovan@collabora.co.uk> | 2012-09-27 16:14:03 -0400 |
commit | 9a5e94dbb4aa306742a47cbbcb0a44d4fc77a9e4 (patch) | |
tree | df4fc293e1411287fbbadc083c50ea85d956196b /net/bluetooth/a2mp.c | |
parent | 0d868de9d8760c76f6d4c6c777935c05ef272caa (diff) |
Bluetooth: A2MP: Process A2MP Get AMP Assoc Rsp
When receiving A2MP Get AMP Assoc Response save assoc data to remote
AMP controller list and prepare for creating physical link.
Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
Signed-off-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
Diffstat (limited to 'net/bluetooth/a2mp.c')
-rw-r--r-- | net/bluetooth/a2mp.c | 60 |
1 files changed, 59 insertions, 1 deletions
diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c index 594df9643365..d0fde05e8b17 100644 --- a/net/bluetooth/a2mp.c +++ b/net/bluetooth/a2mp.c | |||
@@ -343,6 +343,61 @@ done: | |||
343 | return 0; | 343 | return 0; |
344 | } | 344 | } |
345 | 345 | ||
346 | static int a2mp_getampassoc_rsp(struct amp_mgr *mgr, struct sk_buff *skb, | ||
347 | struct a2mp_cmd *hdr) | ||
348 | { | ||
349 | struct a2mp_amp_assoc_rsp *rsp = (void *) skb->data; | ||
350 | u16 len = le16_to_cpu(hdr->len); | ||
351 | struct hci_dev *hdev; | ||
352 | struct amp_ctrl *ctrl; | ||
353 | struct hci_conn *hcon; | ||
354 | |||
355 | if (len < sizeof(*rsp)) | ||
356 | return -EINVAL; | ||
357 | |||
358 | BT_DBG("id %d status 0x%2.2x assoc len %u", rsp->id, rsp->status, | ||
359 | len - sizeof(*rsp)); | ||
360 | |||
361 | if (rsp->status) | ||
362 | return -EINVAL; | ||
363 | |||
364 | /* Save remote ASSOC data */ | ||
365 | ctrl = amp_ctrl_lookup(mgr, rsp->id); | ||
366 | if (ctrl) { | ||
367 | u8 *assoc, assoc_len = len - sizeof(*rsp); | ||
368 | |||
369 | assoc = kzalloc(assoc_len, GFP_KERNEL); | ||
370 | if (!assoc) { | ||
371 | amp_ctrl_put(ctrl); | ||
372 | return -ENOMEM; | ||
373 | } | ||
374 | |||
375 | memcpy(assoc, rsp->amp_assoc, assoc_len); | ||
376 | ctrl->assoc = assoc; | ||
377 | ctrl->assoc_len = assoc_len; | ||
378 | ctrl->assoc_rem_len = assoc_len; | ||
379 | ctrl->assoc_len_so_far = 0; | ||
380 | |||
381 | amp_ctrl_put(ctrl); | ||
382 | } | ||
383 | |||
384 | /* Create Phys Link */ | ||
385 | hdev = hci_dev_get(rsp->id); | ||
386 | if (!hdev) | ||
387 | return -EINVAL; | ||
388 | |||
389 | hcon = phylink_add(hdev, mgr, rsp->id); | ||
390 | if (!hcon) | ||
391 | goto done; | ||
392 | |||
393 | BT_DBG("Created hcon %p: loc:%d -> rem:%d", hcon, hdev->id, rsp->id); | ||
394 | |||
395 | done: | ||
396 | hci_dev_put(hdev); | ||
397 | skb_pull(skb, len); | ||
398 | return 0; | ||
399 | } | ||
400 | |||
346 | static int a2mp_createphyslink_req(struct amp_mgr *mgr, struct sk_buff *skb, | 401 | static int a2mp_createphyslink_req(struct amp_mgr *mgr, struct sk_buff *skb, |
347 | struct a2mp_cmd *hdr) | 402 | struct a2mp_cmd *hdr) |
348 | { | 403 | { |
@@ -502,8 +557,11 @@ static int a2mp_chan_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb) | |||
502 | err = a2mp_getinfo_rsp(mgr, skb, hdr); | 557 | err = a2mp_getinfo_rsp(mgr, skb, hdr); |
503 | break; | 558 | break; |
504 | 559 | ||
505 | case A2MP_CHANGE_RSP: | ||
506 | case A2MP_GETAMPASSOC_RSP: | 560 | case A2MP_GETAMPASSOC_RSP: |
561 | err = a2mp_getampassoc_rsp(mgr, skb, hdr); | ||
562 | break; | ||
563 | |||
564 | case A2MP_CHANGE_RSP: | ||
507 | case A2MP_CREATEPHYSLINK_RSP: | 565 | case A2MP_CREATEPHYSLINK_RSP: |
508 | case A2MP_DISCONNPHYSLINK_RSP: | 566 | case A2MP_DISCONNPHYSLINK_RSP: |
509 | err = a2mp_cmd_rsp(mgr, skb, hdr); | 567 | err = a2mp_cmd_rsp(mgr, skb, hdr); |