aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorAndrei Emeltchenko <andrei.emeltchenko@intel.com>2012-09-27 10:26:09 -0400
committerGustavo Padovan <gustavo.padovan@collabora.co.uk>2012-09-27 16:10:32 -0400
commit903e45411099ae8292f5ce637ad0c72f6fef61db (patch)
tree7e04801dc8623c17c415d1c14221682867be6389 /net
parent8e2a0d92c56ec6955526a8b60838c9b00f70540d (diff)
Bluetooth: AMP: Use HCI cmd to Read Loc AMP Assoc
When receiving A2MP Get AMP Assoc Request execute Read Local AMP Assoc HCI command to AMP controller. If the AMP Assoc data is larger than it can fit to HCI event only fragment is read. When all fragments are read send A2MP Get AMP Assoc Response. 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/Makefile2
-rw-r--r--net/bluetooth/a2mp.c56
-rw-r--r--net/bluetooth/amp.c45
-rw-r--r--net/bluetooth/hci_event.c41
4 files changed, 138 insertions, 6 deletions
diff --git a/net/bluetooth/Makefile b/net/bluetooth/Makefile
index fa6d94a4602a..dea6a287daca 100644
--- a/net/bluetooth/Makefile
+++ b/net/bluetooth/Makefile
@@ -10,4 +10,4 @@ obj-$(CONFIG_BT_HIDP) += hidp/
10 10
11bluetooth-y := af_bluetooth.o hci_core.o hci_conn.o hci_event.o mgmt.o \ 11bluetooth-y := af_bluetooth.o hci_core.o hci_conn.o hci_event.o mgmt.o \
12 hci_sock.o hci_sysfs.o l2cap_core.o l2cap_sock.o smp.o sco.o lib.o \ 12 hci_sock.o hci_sysfs.o l2cap_core.o l2cap_sock.o smp.o sco.o lib.o \
13 a2mp.o 13 a2mp.o amp.o
diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
index 0e97b3b42ab1..71400612843d 100644
--- a/net/bluetooth/a2mp.c
+++ b/net/bluetooth/a2mp.c
@@ -16,6 +16,7 @@
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#include <net/bluetooth/a2mp.h>
19#include <net/bluetooth/amp.h>
19 20
20/* Global AMP Manager list */ 21/* Global AMP Manager list */
21LIST_HEAD(amp_mgr_list); 22LIST_HEAD(amp_mgr_list);
@@ -218,26 +219,37 @@ static int a2mp_getampassoc_req(struct amp_mgr *mgr, struct sk_buff *skb,
218{ 219{
219 struct a2mp_amp_assoc_req *req = (void *) skb->data; 220 struct a2mp_amp_assoc_req *req = (void *) skb->data;
220 struct hci_dev *hdev; 221 struct hci_dev *hdev;
222 struct amp_mgr *tmp;
221 223
222 if (le16_to_cpu(hdr->len) < sizeof(*req)) 224 if (le16_to_cpu(hdr->len) < sizeof(*req))
223 return -EINVAL; 225 return -EINVAL;
224 226
225 BT_DBG("id %d", req->id); 227 BT_DBG("id %d", req->id);
226 228
229 /* Make sure that other request is not processed */
230 tmp = amp_mgr_lookup_by_state(READ_LOC_AMP_ASSOC);
231
227 hdev = hci_dev_get(req->id); 232 hdev = hci_dev_get(req->id);
228 if (!hdev || hdev->amp_type == HCI_BREDR) { 233 if (!hdev || hdev->amp_type == HCI_BREDR || tmp) {
229 struct a2mp_amp_assoc_rsp rsp; 234 struct a2mp_amp_assoc_rsp rsp;
230 rsp.id = req->id; 235 rsp.id = req->id;
231 rsp.status = A2MP_STATUS_INVALID_CTRL_ID; 236
237 if (tmp) {
238 rsp.status = A2MP_STATUS_COLLISION_OCCURED;
239 amp_mgr_put(tmp);
240 } else {
241 rsp.status = A2MP_STATUS_INVALID_CTRL_ID;
242 }
232 243
233 a2mp_send(mgr, A2MP_GETAMPASSOC_RSP, hdr->ident, sizeof(rsp), 244 a2mp_send(mgr, A2MP_GETAMPASSOC_RSP, hdr->ident, sizeof(rsp),
234 &rsp); 245 &rsp);
235 goto clean; 246
247 goto done;
236 } 248 }
237 249
238 /* Placeholder for HCI Read AMP Assoc */ 250 amp_read_loc_assoc(hdev, mgr);
239 251
240clean: 252done:
241 if (hdev) 253 if (hdev)
242 hci_dev_put(hdev); 254 hci_dev_put(hdev);
243 255
@@ -624,3 +636,37 @@ void a2mp_send_getinfo_rsp(struct hci_dev *hdev)
624 a2mp_send(mgr, A2MP_GETINFO_RSP, mgr->ident, sizeof(rsp), &rsp); 636 a2mp_send(mgr, A2MP_GETINFO_RSP, mgr->ident, sizeof(rsp), &rsp);
625 amp_mgr_put(mgr); 637 amp_mgr_put(mgr);
626} 638}
639
640void a2mp_send_getampassoc_rsp(struct hci_dev *hdev, u8 status)
641{
642 struct amp_mgr *mgr;
643 struct amp_assoc *loc_assoc = &hdev->loc_assoc;
644 struct a2mp_amp_assoc_rsp *rsp;
645 size_t len;
646
647 mgr = amp_mgr_lookup_by_state(READ_LOC_AMP_ASSOC);
648 if (!mgr)
649 return;
650
651 BT_DBG("%s mgr %p", hdev->name, mgr);
652
653 len = sizeof(struct a2mp_amp_assoc_rsp) + loc_assoc->len;
654 rsp = kzalloc(len, GFP_KERNEL);
655 if (!rsp) {
656 amp_mgr_put(mgr);
657 return;
658 }
659
660 rsp->id = hdev->id;
661
662 if (status) {
663 rsp->status = A2MP_STATUS_INVALID_CTRL_ID;
664 } else {
665 rsp->status = A2MP_STATUS_SUCCESS;
666 memcpy(rsp->amp_assoc, loc_assoc->data, loc_assoc->len);
667 }
668
669 a2mp_send(mgr, A2MP_GETAMPASSOC_RSP, mgr->ident, len, rsp);
670 amp_mgr_put(mgr);
671 kfree(rsp);
672}
diff --git a/net/bluetooth/amp.c b/net/bluetooth/amp.c
new file mode 100644
index 000000000000..2d4e79ee06a5
--- /dev/null
+++ b/net/bluetooth/amp.c
@@ -0,0 +1,45 @@
1/*
2 Copyright (c) 2011,2012 Intel Corp.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License version 2 and
6 only version 2 as published by the Free Software Foundation.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12*/
13
14#include <net/bluetooth/bluetooth.h>
15#include <net/bluetooth/hci.h>
16#include <net/bluetooth/hci_core.h>
17#include <net/bluetooth/a2mp.h>
18#include <net/bluetooth/amp.h>
19
20void amp_read_loc_assoc_frag(struct hci_dev *hdev, u8 phy_handle)
21{
22 struct hci_cp_read_local_amp_assoc cp;
23 struct amp_assoc *loc_assoc = &hdev->loc_assoc;
24
25 BT_DBG("%s handle %d", hdev->name, phy_handle);
26
27 cp.phy_handle = phy_handle;
28 cp.max_len = cpu_to_le16(hdev->amp_assoc_size);
29 cp.len_so_far = cpu_to_le16(loc_assoc->offset);
30
31 hci_send_cmd(hdev, HCI_OP_READ_LOCAL_AMP_ASSOC, sizeof(cp), &cp);
32}
33
34void amp_read_loc_assoc(struct hci_dev *hdev, struct amp_mgr *mgr)
35{
36 struct hci_cp_read_local_amp_assoc cp;
37
38 memset(&hdev->loc_assoc, 0, sizeof(struct amp_assoc));
39 memset(&cp, 0, sizeof(cp));
40
41 cp.max_len = cpu_to_le16(hdev->amp_assoc_size);
42
43 mgr->state = READ_LOC_AMP_ASSOC;
44 hci_send_cmd(hdev, HCI_OP_READ_LOCAL_AMP_ASSOC, sizeof(cp), &cp);
45}
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index eb45774165f4..a4240f7a142e 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -31,6 +31,7 @@
31#include <net/bluetooth/hci_core.h> 31#include <net/bluetooth/hci_core.h>
32#include <net/bluetooth/mgmt.h> 32#include <net/bluetooth/mgmt.h>
33#include <net/bluetooth/a2mp.h> 33#include <net/bluetooth/a2mp.h>
34#include <net/bluetooth/amp.h>
34 35
35/* Handle HCI Event packets */ 36/* Handle HCI Event packets */
36 37
@@ -866,6 +867,42 @@ a2mp_rsp:
866 a2mp_send_getinfo_rsp(hdev); 867 a2mp_send_getinfo_rsp(hdev);
867} 868}
868 869
870static void hci_cc_read_local_amp_assoc(struct hci_dev *hdev,
871 struct sk_buff *skb)
872{
873 struct hci_rp_read_local_amp_assoc *rp = (void *) skb->data;
874 struct amp_assoc *assoc = &hdev->loc_assoc;
875 size_t rem_len, frag_len;
876
877 BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
878
879 if (rp->status)
880 goto a2mp_rsp;
881
882 frag_len = skb->len - sizeof(*rp);
883 rem_len = __le16_to_cpu(rp->rem_len);
884
885 if (rem_len > frag_len) {
886 BT_DBG("frag_len %d rem_len %d", frag_len, rem_len);
887
888 memcpy(assoc->data + assoc->offset, rp->frag, frag_len);
889 assoc->offset += frag_len;
890
891 /* Read other fragments */
892 amp_read_loc_assoc_frag(hdev, rp->phy_handle);
893
894 return;
895 }
896
897 memcpy(assoc->data + assoc->offset, rp->frag, rem_len);
898 assoc->len = assoc->offset + rem_len;
899 assoc->offset = 0;
900
901a2mp_rsp:
902 /* Send A2MP Rsp when all fragments are received */
903 a2mp_send_getampassoc_rsp(hdev, rp->status);
904}
905
869static void hci_cc_delete_stored_link_key(struct hci_dev *hdev, 906static void hci_cc_delete_stored_link_key(struct hci_dev *hdev,
870 struct sk_buff *skb) 907 struct sk_buff *skb)
871{ 908{
@@ -2318,6 +2355,10 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
2318 hci_cc_read_local_amp_info(hdev, skb); 2355 hci_cc_read_local_amp_info(hdev, skb);
2319 break; 2356 break;
2320 2357
2358 case HCI_OP_READ_LOCAL_AMP_ASSOC:
2359 hci_cc_read_local_amp_assoc(hdev, skb);
2360 break;
2361
2321 case HCI_OP_DELETE_STORED_LINK_KEY: 2362 case HCI_OP_DELETE_STORED_LINK_KEY:
2322 hci_cc_delete_stored_link_key(hdev, skb); 2363 hci_cc_delete_stored_link_key(hdev, skb);
2323 break; 2364 break;