aboutsummaryrefslogtreecommitdiffstats
path: root/net/bluetooth
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 /net/bluetooth
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>
Diffstat (limited to 'net/bluetooth')
-rw-r--r--net/bluetooth/a2mp.c85
1 files changed, 85 insertions, 0 deletions
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: