aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrei Emeltchenko <andrei.emeltchenko@intel.com>2012-05-29 06:59:09 -0400
committerJohan Hedberg <johan.hedberg@intel.com>2012-06-04 23:34:12 -0400
commit8598d064cbf22b2d84c7cd8a9fcb97138baffe3f (patch)
tree4ac83c774867460958b74416144b44004bfd05c1
parent21dbd2ce35f6d2b4aa5363be6c839cdb50644e11 (diff)
Bluetooth: A2MP: Process A2MP Discover Request
Adds helper functions to count HCI devs and process A2MP Discover Request, code makes sure that first controller in the list is BREDR one. Trace is shown below: ... > ACL data: handle 11 flags 0x02 dlen 16 A2MP: Discover req: mtu/mps 670 mask: 0x0000 < ACL data: handle 11 flags 0x00 dlen 22 A2MP: Discover rsp: mtu/mps 670 mask: 0x0000 Controller list: id 0 type 0 (BR-EDR) status 0x01 (Bluetooth only) id 1 type 1 (802.11 AMP) status 0x01 (Bluetooth only) ... Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com> Signed-off-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
-rw-r--r--include/net/bluetooth/a2mp.h2
-rw-r--r--include/net/bluetooth/hci.h3
-rw-r--r--include/net/bluetooth/hci_core.h13
-rw-r--r--net/bluetooth/a2mp.c85
4 files changed, 103 insertions, 0 deletions
diff --git a/include/net/bluetooth/a2mp.h b/include/net/bluetooth/a2mp.h
index 391acd7a67d4..96f9cc2cf59b 100644
--- a/include/net/bluetooth/a2mp.h
+++ b/include/net/bluetooth/a2mp.h
@@ -15,6 +15,8 @@
15#ifndef __A2MP_H 15#ifndef __A2MP_H
16#define __A2MP_H 16#define __A2MP_H
17 17
18#define A2MP_FEAT_EXT 0x8000
19
18struct amp_mgr { 20struct amp_mgr {
19 struct l2cap_conn *l2cap_conn; 21 struct l2cap_conn *l2cap_conn;
20 struct l2cap_chan *a2mp_chan; 22 struct l2cap_chan *a2mp_chan;
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index de09a26e4223..66af2c6193d5 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -59,6 +59,9 @@
59#define HCI_BREDR 0x00 59#define HCI_BREDR 0x00
60#define HCI_AMP 0x01 60#define HCI_AMP 0x01
61 61
62/* First BR/EDR Controller shall have ID = 0 */
63#define HCI_BREDR_ID 0
64
62/* HCI device quirks */ 65/* HCI device quirks */
63enum { 66enum {
64 HCI_QUIRK_RESET_ON_CLOSE, 67 HCI_QUIRK_RESET_ON_CLOSE,
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 6e64b76e30aa..20fd57367ddc 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -641,6 +641,19 @@ static inline void hci_set_drvdata(struct hci_dev *hdev, void *data)
641 dev_set_drvdata(&hdev->dev, data); 641 dev_set_drvdata(&hdev->dev, data);
642} 642}
643 643
644/* hci_dev_list shall be locked */
645static inline uint8_t __hci_num_ctrl(void)
646{
647 uint8_t count = 0;
648 struct list_head *p;
649
650 list_for_each(p, &hci_dev_list) {
651 count++;
652 }
653
654 return count;
655}
656
644struct hci_dev *hci_dev_get(int index); 657struct hci_dev *hci_dev_get(int index);
645struct hci_dev *hci_get_route(bdaddr_t *src, bdaddr_t *dst); 658struct hci_dev *hci_get_route(bdaddr_t *src, bdaddr_t *dst);
646 659
diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
index 188b42120074..1cc920a62b0f 100644
--- a/net/bluetooth/a2mp.c
+++ b/net/bluetooth/a2mp.c
@@ -63,6 +63,36 @@ static void a2mp_send(struct amp_mgr *mgr, u8 code, u8 ident, u16 len,
63 kfree(cmd); 63 kfree(cmd);
64} 64}
65 65
66static inline void __a2mp_cl_bredr(struct a2mp_cl *cl)
67{
68 cl->id = 0;
69 cl->type = 0;
70 cl->status = 1;
71}
72
73/* hci_dev_list shall be locked */
74static void __a2mp_add_cl(struct amp_mgr *mgr, struct a2mp_cl *cl, u8 num_ctrl)
75{
76 int i = 0;
77 struct hci_dev *hdev;
78
79 __a2mp_cl_bredr(cl);
80
81 list_for_each_entry(hdev, &hci_dev_list, list) {
82 /* Iterate through AMP controllers */
83 if (hdev->id == HCI_BREDR_ID)
84 continue;
85
86 /* Starting from second entry */
87 if (++i >= num_ctrl)
88 return;
89
90 cl[i].id = hdev->id;
91 cl[i].type = hdev->amp_type;
92 cl[i].status = hdev->amp_status;
93 }
94}
95
66/* Processing A2MP messages */ 96/* Processing A2MP messages */
67static int a2mp_command_rej(struct amp_mgr *mgr, struct sk_buff *skb, 97static int a2mp_command_rej(struct amp_mgr *mgr, struct sk_buff *skb,
68 struct a2mp_cmd *hdr) 98 struct a2mp_cmd *hdr)
@@ -79,6 +109,58 @@ static int a2mp_command_rej(struct amp_mgr *mgr, struct sk_buff *skb,
79 return 0; 109 return 0;
80} 110}
81 111
112static int a2mp_discover_req(struct amp_mgr *mgr, struct sk_buff *skb,
113 struct a2mp_cmd *hdr)
114{
115 struct a2mp_discov_req *req = (void *) skb->data;
116 u16 len = le16_to_cpu(hdr->len);
117 struct a2mp_discov_rsp *rsp;
118 u16 ext_feat;
119 u8 num_ctrl;
120
121 if (len < sizeof(*req))
122 return -EINVAL;
123
124 skb_pull(skb, sizeof(*req));
125
126 ext_feat = le16_to_cpu(req->ext_feat);
127
128 BT_DBG("mtu %d efm 0x%4.4x", le16_to_cpu(req->mtu), ext_feat);
129
130 /* check that packet is not broken for now */
131 while (ext_feat & A2MP_FEAT_EXT) {
132 if (len < sizeof(ext_feat))
133 return -EINVAL;
134
135 ext_feat = get_unaligned_le16(skb->data);
136 BT_DBG("efm 0x%4.4x", ext_feat);
137 len -= sizeof(ext_feat);
138 skb_pull(skb, sizeof(ext_feat));
139 }
140
141 read_lock(&hci_dev_list_lock);
142
143 num_ctrl = __hci_num_ctrl();
144 len = num_ctrl * sizeof(struct a2mp_cl) + sizeof(*rsp);
145 rsp = kmalloc(len, GFP_ATOMIC);
146 if (!rsp) {
147 read_unlock(&hci_dev_list_lock);
148 return -ENOMEM;
149 }
150
151 rsp->mtu = __constant_cpu_to_le16(L2CAP_A2MP_DEFAULT_MTU);
152 rsp->ext_feat = 0;
153
154 __a2mp_add_cl(mgr, rsp->cl, num_ctrl);
155
156 read_unlock(&hci_dev_list_lock);
157
158 a2mp_send(mgr, A2MP_DISCOVER_RSP, hdr->ident, len, rsp);
159
160 kfree(rsp);
161 return 0;
162}
163
82/* Handle A2MP signalling */ 164/* Handle A2MP signalling */
83static int a2mp_chan_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb) 165static int a2mp_chan_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb)
84{ 166{
@@ -109,6 +191,9 @@ static int a2mp_chan_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb)
109 break; 191 break;
110 192
111 case A2MP_DISCOVER_REQ: 193 case A2MP_DISCOVER_REQ:
194 err = a2mp_discover_req(mgr, skb, hdr);
195 break;
196
112 case A2MP_CHANGE_NOTIFY: 197 case A2MP_CHANGE_NOTIFY:
113 case A2MP_GETINFO_REQ: 198 case A2MP_GETINFO_REQ:
114 case A2MP_GETAMPASSOC_REQ: 199 case A2MP_GETAMPASSOC_REQ: