aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/bluetooth/a2mp.h2
-rw-r--r--include/net/bluetooth/amp.h21
-rw-r--r--include/net/bluetooth/hci.h2
-rw-r--r--include/net/bluetooth/hci_core.h8
-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
8 files changed, 171 insertions, 6 deletions
diff --git a/include/net/bluetooth/a2mp.h b/include/net/bluetooth/a2mp.h
index af594685112e..d5476719fa4c 100644
--- a/include/net/bluetooth/a2mp.h
+++ b/include/net/bluetooth/a2mp.h
@@ -21,6 +21,7 @@
21 21
22enum amp_mgr_state { 22enum amp_mgr_state {
23 READ_LOC_AMP_INFO, 23 READ_LOC_AMP_INFO,
24 READ_LOC_AMP_ASSOC,
24}; 25};
25 26
26struct amp_mgr { 27struct amp_mgr {
@@ -134,5 +135,6 @@ struct l2cap_chan *a2mp_channel_create(struct l2cap_conn *conn,
134struct amp_mgr *amp_mgr_lookup_by_state(u8 state); 135struct amp_mgr *amp_mgr_lookup_by_state(u8 state);
135void a2mp_send(struct amp_mgr *mgr, u8 code, u8 ident, u16 len, void *data); 136void a2mp_send(struct amp_mgr *mgr, u8 code, u8 ident, u16 len, void *data);
136void a2mp_send_getinfo_rsp(struct hci_dev *hdev); 137void a2mp_send_getinfo_rsp(struct hci_dev *hdev);
138void a2mp_send_getampassoc_rsp(struct hci_dev *hdev, u8 status);
137 139
138#endif /* __A2MP_H */ 140#endif /* __A2MP_H */
diff --git a/include/net/bluetooth/amp.h b/include/net/bluetooth/amp.h
new file mode 100644
index 000000000000..e8616751bc81
--- /dev/null
+++ b/include/net/bluetooth/amp.h
@@ -0,0 +1,21 @@
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#ifndef __AMP_H
15#define __AMP_H
16
17void amp_read_loc_info(struct hci_dev *hdev, struct amp_mgr *mgr);
18void amp_read_loc_assoc_frag(struct hci_dev *hdev, u8 phy_handle);
19void amp_read_loc_assoc(struct hci_dev *hdev, struct amp_mgr *mgr);
20
21#endif /* __AMP_H */
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index 4be26abf6dad..ccc08e57c107 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -33,6 +33,8 @@
33#define HCI_LINK_KEY_SIZE 16 33#define HCI_LINK_KEY_SIZE 16
34#define HCI_AMP_LINK_KEY_SIZE (2 * HCI_LINK_KEY_SIZE) 34#define HCI_AMP_LINK_KEY_SIZE (2 * HCI_LINK_KEY_SIZE)
35 35
36#define HCI_MAX_AMP_ASSOC_SIZE 672
37
36/* HCI dev events */ 38/* HCI dev events */
37#define HCI_DEV_REG 1 39#define HCI_DEV_REG 1
38#define HCI_DEV_UNREG 2 40#define HCI_DEV_UNREG 2
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index e7d454609881..b1c7d0607244 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -124,6 +124,12 @@ struct le_scan_params {
124 124
125#define HCI_MAX_SHORT_NAME_LENGTH 10 125#define HCI_MAX_SHORT_NAME_LENGTH 10
126 126
127struct amp_assoc {
128 __u16 len;
129 __u16 offset;
130 __u8 data[HCI_MAX_AMP_ASSOC_SIZE];
131};
132
127#define NUM_REASSEMBLY 4 133#define NUM_REASSEMBLY 4
128struct hci_dev { 134struct hci_dev {
129 struct list_head list; 135 struct list_head list;
@@ -177,6 +183,8 @@ struct hci_dev {
177 __u32 amp_max_flush_to; 183 __u32 amp_max_flush_to;
178 __u32 amp_be_flush_to; 184 __u32 amp_be_flush_to;
179 185
186 struct amp_assoc loc_assoc;
187
180 __u8 flow_ctl_mode; 188 __u8 flow_ctl_mode;
181 189
182 unsigned int auto_accept_delay; 190 unsigned int auto_accept_delay;
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;