diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /net/bluetooth/hci_event.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'net/bluetooth/hci_event.c')
-rw-r--r-- | net/bluetooth/hci_event.c | 1044 |
1 files changed, 1044 insertions, 0 deletions
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c new file mode 100644 index 000000000000..8ccba8ee9979 --- /dev/null +++ b/net/bluetooth/hci_event.c | |||
@@ -0,0 +1,1044 @@ | |||
1 | /* | ||
2 | BlueZ - Bluetooth protocol stack for Linux | ||
3 | Copyright (C) 2000-2001 Qualcomm Incorporated | ||
4 | |||
5 | Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com> | ||
6 | |||
7 | This program is free software; you can redistribute it and/or modify | ||
8 | it under the terms of the GNU General Public License version 2 as | ||
9 | published by the Free Software Foundation; | ||
10 | |||
11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | ||
12 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
13 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. | ||
14 | IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY | ||
15 | CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES | ||
16 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
17 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
18 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
19 | |||
20 | ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, | ||
21 | COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS | ||
22 | SOFTWARE IS DISCLAIMED. | ||
23 | */ | ||
24 | |||
25 | /* Bluetooth HCI event handling. */ | ||
26 | |||
27 | #include <linux/config.h> | ||
28 | #include <linux/module.h> | ||
29 | |||
30 | #include <linux/types.h> | ||
31 | #include <linux/errno.h> | ||
32 | #include <linux/kernel.h> | ||
33 | #include <linux/major.h> | ||
34 | #include <linux/sched.h> | ||
35 | #include <linux/slab.h> | ||
36 | #include <linux/poll.h> | ||
37 | #include <linux/fcntl.h> | ||
38 | #include <linux/init.h> | ||
39 | #include <linux/skbuff.h> | ||
40 | #include <linux/interrupt.h> | ||
41 | #include <linux/notifier.h> | ||
42 | #include <net/sock.h> | ||
43 | |||
44 | #include <asm/system.h> | ||
45 | #include <asm/uaccess.h> | ||
46 | #include <asm/unaligned.h> | ||
47 | |||
48 | #include <net/bluetooth/bluetooth.h> | ||
49 | #include <net/bluetooth/hci_core.h> | ||
50 | |||
51 | #ifndef CONFIG_BT_HCI_CORE_DEBUG | ||
52 | #undef BT_DBG | ||
53 | #define BT_DBG(D...) | ||
54 | #endif | ||
55 | |||
56 | /* Handle HCI Event packets */ | ||
57 | |||
58 | /* Command Complete OGF LINK_CTL */ | ||
59 | static void hci_cc_link_ctl(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb) | ||
60 | { | ||
61 | __u8 status; | ||
62 | |||
63 | BT_DBG("%s ocf 0x%x", hdev->name, ocf); | ||
64 | |||
65 | switch (ocf) { | ||
66 | case OCF_INQUIRY_CANCEL: | ||
67 | status = *((__u8 *) skb->data); | ||
68 | |||
69 | if (status) { | ||
70 | BT_DBG("%s Inquiry cancel error: status 0x%x", hdev->name, status); | ||
71 | } else { | ||
72 | clear_bit(HCI_INQUIRY, &hdev->flags); | ||
73 | hci_req_complete(hdev, status); | ||
74 | } | ||
75 | break; | ||
76 | |||
77 | default: | ||
78 | BT_DBG("%s Command complete: ogf LINK_CTL ocf %x", hdev->name, ocf); | ||
79 | break; | ||
80 | } | ||
81 | } | ||
82 | |||
83 | /* Command Complete OGF LINK_POLICY */ | ||
84 | static void hci_cc_link_policy(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb) | ||
85 | { | ||
86 | struct hci_conn *conn; | ||
87 | struct hci_rp_role_discovery *rd; | ||
88 | |||
89 | BT_DBG("%s ocf 0x%x", hdev->name, ocf); | ||
90 | |||
91 | switch (ocf) { | ||
92 | case OCF_ROLE_DISCOVERY: | ||
93 | rd = (void *) skb->data; | ||
94 | |||
95 | if (rd->status) | ||
96 | break; | ||
97 | |||
98 | hci_dev_lock(hdev); | ||
99 | |||
100 | conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(rd->handle)); | ||
101 | if (conn) { | ||
102 | if (rd->role) | ||
103 | conn->link_mode &= ~HCI_LM_MASTER; | ||
104 | else | ||
105 | conn->link_mode |= HCI_LM_MASTER; | ||
106 | } | ||
107 | |||
108 | hci_dev_unlock(hdev); | ||
109 | break; | ||
110 | |||
111 | default: | ||
112 | BT_DBG("%s: Command complete: ogf LINK_POLICY ocf %x", | ||
113 | hdev->name, ocf); | ||
114 | break; | ||
115 | } | ||
116 | } | ||
117 | |||
118 | /* Command Complete OGF HOST_CTL */ | ||
119 | static void hci_cc_host_ctl(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb) | ||
120 | { | ||
121 | __u8 status, param; | ||
122 | __u16 setting; | ||
123 | struct hci_rp_read_voice_setting *vs; | ||
124 | void *sent; | ||
125 | |||
126 | BT_DBG("%s ocf 0x%x", hdev->name, ocf); | ||
127 | |||
128 | switch (ocf) { | ||
129 | case OCF_RESET: | ||
130 | status = *((__u8 *) skb->data); | ||
131 | hci_req_complete(hdev, status); | ||
132 | break; | ||
133 | |||
134 | case OCF_SET_EVENT_FLT: | ||
135 | status = *((__u8 *) skb->data); | ||
136 | if (status) { | ||
137 | BT_DBG("%s SET_EVENT_FLT failed %d", hdev->name, status); | ||
138 | } else { | ||
139 | BT_DBG("%s SET_EVENT_FLT succeseful", hdev->name); | ||
140 | } | ||
141 | break; | ||
142 | |||
143 | case OCF_WRITE_AUTH_ENABLE: | ||
144 | sent = hci_sent_cmd_data(hdev, OGF_HOST_CTL, OCF_WRITE_AUTH_ENABLE); | ||
145 | if (!sent) | ||
146 | break; | ||
147 | |||
148 | status = *((__u8 *) skb->data); | ||
149 | param = *((__u8 *) sent); | ||
150 | |||
151 | if (!status) { | ||
152 | if (param == AUTH_ENABLED) | ||
153 | set_bit(HCI_AUTH, &hdev->flags); | ||
154 | else | ||
155 | clear_bit(HCI_AUTH, &hdev->flags); | ||
156 | } | ||
157 | hci_req_complete(hdev, status); | ||
158 | break; | ||
159 | |||
160 | case OCF_WRITE_ENCRYPT_MODE: | ||
161 | sent = hci_sent_cmd_data(hdev, OGF_HOST_CTL, OCF_WRITE_ENCRYPT_MODE); | ||
162 | if (!sent) | ||
163 | break; | ||
164 | |||
165 | status = *((__u8 *) skb->data); | ||
166 | param = *((__u8 *) sent); | ||
167 | |||
168 | if (!status) { | ||
169 | if (param) | ||
170 | set_bit(HCI_ENCRYPT, &hdev->flags); | ||
171 | else | ||
172 | clear_bit(HCI_ENCRYPT, &hdev->flags); | ||
173 | } | ||
174 | hci_req_complete(hdev, status); | ||
175 | break; | ||
176 | |||
177 | case OCF_WRITE_CA_TIMEOUT: | ||
178 | status = *((__u8 *) skb->data); | ||
179 | if (status) { | ||
180 | BT_DBG("%s OCF_WRITE_CA_TIMEOUT failed %d", hdev->name, status); | ||
181 | } else { | ||
182 | BT_DBG("%s OCF_WRITE_CA_TIMEOUT succeseful", hdev->name); | ||
183 | } | ||
184 | break; | ||
185 | |||
186 | case OCF_WRITE_PG_TIMEOUT: | ||
187 | status = *((__u8 *) skb->data); | ||
188 | if (status) { | ||
189 | BT_DBG("%s OCF_WRITE_PG_TIMEOUT failed %d", hdev->name, status); | ||
190 | } else { | ||
191 | BT_DBG("%s: OCF_WRITE_PG_TIMEOUT succeseful", hdev->name); | ||
192 | } | ||
193 | break; | ||
194 | |||
195 | case OCF_WRITE_SCAN_ENABLE: | ||
196 | sent = hci_sent_cmd_data(hdev, OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE); | ||
197 | if (!sent) | ||
198 | break; | ||
199 | |||
200 | status = *((__u8 *) skb->data); | ||
201 | param = *((__u8 *) sent); | ||
202 | |||
203 | BT_DBG("param 0x%x", param); | ||
204 | |||
205 | if (!status) { | ||
206 | clear_bit(HCI_PSCAN, &hdev->flags); | ||
207 | clear_bit(HCI_ISCAN, &hdev->flags); | ||
208 | if (param & SCAN_INQUIRY) | ||
209 | set_bit(HCI_ISCAN, &hdev->flags); | ||
210 | |||
211 | if (param & SCAN_PAGE) | ||
212 | set_bit(HCI_PSCAN, &hdev->flags); | ||
213 | } | ||
214 | hci_req_complete(hdev, status); | ||
215 | break; | ||
216 | |||
217 | case OCF_READ_VOICE_SETTING: | ||
218 | vs = (struct hci_rp_read_voice_setting *) skb->data; | ||
219 | |||
220 | if (vs->status) { | ||
221 | BT_DBG("%s READ_VOICE_SETTING failed %d", hdev->name, vs->status); | ||
222 | break; | ||
223 | } | ||
224 | |||
225 | setting = __le16_to_cpu(vs->voice_setting); | ||
226 | |||
227 | if (hdev->voice_setting != setting ) { | ||
228 | hdev->voice_setting = setting; | ||
229 | |||
230 | BT_DBG("%s: voice setting 0x%04x", hdev->name, setting); | ||
231 | |||
232 | if (hdev->notify) { | ||
233 | tasklet_disable(&hdev->tx_task); | ||
234 | hdev->notify(hdev, HCI_NOTIFY_VOICE_SETTING); | ||
235 | tasklet_enable(&hdev->tx_task); | ||
236 | } | ||
237 | } | ||
238 | break; | ||
239 | |||
240 | case OCF_WRITE_VOICE_SETTING: | ||
241 | sent = hci_sent_cmd_data(hdev, OGF_HOST_CTL, OCF_WRITE_VOICE_SETTING); | ||
242 | if (!sent) | ||
243 | break; | ||
244 | |||
245 | status = *((__u8 *) skb->data); | ||
246 | setting = __le16_to_cpu(get_unaligned((__u16 *) sent)); | ||
247 | |||
248 | if (!status && hdev->voice_setting != setting) { | ||
249 | hdev->voice_setting = setting; | ||
250 | |||
251 | BT_DBG("%s: voice setting 0x%04x", hdev->name, setting); | ||
252 | |||
253 | if (hdev->notify) { | ||
254 | tasklet_disable(&hdev->tx_task); | ||
255 | hdev->notify(hdev, HCI_NOTIFY_VOICE_SETTING); | ||
256 | tasklet_enable(&hdev->tx_task); | ||
257 | } | ||
258 | } | ||
259 | hci_req_complete(hdev, status); | ||
260 | break; | ||
261 | |||
262 | case OCF_HOST_BUFFER_SIZE: | ||
263 | status = *((__u8 *) skb->data); | ||
264 | if (status) { | ||
265 | BT_DBG("%s OCF_BUFFER_SIZE failed %d", hdev->name, status); | ||
266 | hci_req_complete(hdev, status); | ||
267 | } | ||
268 | break; | ||
269 | |||
270 | default: | ||
271 | BT_DBG("%s Command complete: ogf HOST_CTL ocf %x", hdev->name, ocf); | ||
272 | break; | ||
273 | } | ||
274 | } | ||
275 | |||
276 | /* Command Complete OGF INFO_PARAM */ | ||
277 | static void hci_cc_info_param(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb) | ||
278 | { | ||
279 | struct hci_rp_read_loc_features *lf; | ||
280 | struct hci_rp_read_buffer_size *bs; | ||
281 | struct hci_rp_read_bd_addr *ba; | ||
282 | |||
283 | BT_DBG("%s ocf 0x%x", hdev->name, ocf); | ||
284 | |||
285 | switch (ocf) { | ||
286 | case OCF_READ_LOCAL_FEATURES: | ||
287 | lf = (struct hci_rp_read_loc_features *) skb->data; | ||
288 | |||
289 | if (lf->status) { | ||
290 | BT_DBG("%s READ_LOCAL_FEATURES failed %d", hdev->name, lf->status); | ||
291 | break; | ||
292 | } | ||
293 | |||
294 | memcpy(hdev->features, lf->features, sizeof(hdev->features)); | ||
295 | |||
296 | /* Adjust default settings according to features | ||
297 | * supported by device. */ | ||
298 | if (hdev->features[0] & LMP_3SLOT) | ||
299 | hdev->pkt_type |= (HCI_DM3 | HCI_DH3); | ||
300 | |||
301 | if (hdev->features[0] & LMP_5SLOT) | ||
302 | hdev->pkt_type |= (HCI_DM5 | HCI_DH5); | ||
303 | |||
304 | if (hdev->features[1] & LMP_HV2) | ||
305 | hdev->pkt_type |= (HCI_HV2); | ||
306 | |||
307 | if (hdev->features[1] & LMP_HV3) | ||
308 | hdev->pkt_type |= (HCI_HV3); | ||
309 | |||
310 | BT_DBG("%s: features 0x%x 0x%x 0x%x", hdev->name, lf->features[0], lf->features[1], lf->features[2]); | ||
311 | |||
312 | break; | ||
313 | |||
314 | case OCF_READ_BUFFER_SIZE: | ||
315 | bs = (struct hci_rp_read_buffer_size *) skb->data; | ||
316 | |||
317 | if (bs->status) { | ||
318 | BT_DBG("%s READ_BUFFER_SIZE failed %d", hdev->name, bs->status); | ||
319 | hci_req_complete(hdev, bs->status); | ||
320 | break; | ||
321 | } | ||
322 | |||
323 | hdev->acl_mtu = __le16_to_cpu(bs->acl_mtu); | ||
324 | hdev->sco_mtu = bs->sco_mtu ? bs->sco_mtu : 64; | ||
325 | hdev->acl_pkts = hdev->acl_cnt = __le16_to_cpu(bs->acl_max_pkt); | ||
326 | hdev->sco_pkts = hdev->sco_cnt = __le16_to_cpu(bs->sco_max_pkt); | ||
327 | |||
328 | BT_DBG("%s mtu: acl %d, sco %d max_pkt: acl %d, sco %d", hdev->name, | ||
329 | hdev->acl_mtu, hdev->sco_mtu, hdev->acl_pkts, hdev->sco_pkts); | ||
330 | break; | ||
331 | |||
332 | case OCF_READ_BD_ADDR: | ||
333 | ba = (struct hci_rp_read_bd_addr *) skb->data; | ||
334 | |||
335 | if (!ba->status) { | ||
336 | bacpy(&hdev->bdaddr, &ba->bdaddr); | ||
337 | } else { | ||
338 | BT_DBG("%s: READ_BD_ADDR failed %d", hdev->name, ba->status); | ||
339 | } | ||
340 | |||
341 | hci_req_complete(hdev, ba->status); | ||
342 | break; | ||
343 | |||
344 | default: | ||
345 | BT_DBG("%s Command complete: ogf INFO_PARAM ocf %x", hdev->name, ocf); | ||
346 | break; | ||
347 | } | ||
348 | } | ||
349 | |||
350 | /* Command Status OGF LINK_CTL */ | ||
351 | static inline void hci_cs_create_conn(struct hci_dev *hdev, __u8 status) | ||
352 | { | ||
353 | struct hci_conn *conn; | ||
354 | struct hci_cp_create_conn *cp = hci_sent_cmd_data(hdev, OGF_LINK_CTL, OCF_CREATE_CONN); | ||
355 | |||
356 | if (!cp) | ||
357 | return; | ||
358 | |||
359 | hci_dev_lock(hdev); | ||
360 | |||
361 | conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr); | ||
362 | |||
363 | BT_DBG("%s status 0x%x bdaddr %s conn %p", hdev->name, | ||
364 | status, batostr(&cp->bdaddr), conn); | ||
365 | |||
366 | if (status) { | ||
367 | if (conn && conn->state == BT_CONNECT) { | ||
368 | conn->state = BT_CLOSED; | ||
369 | hci_proto_connect_cfm(conn, status); | ||
370 | hci_conn_del(conn); | ||
371 | } | ||
372 | } else { | ||
373 | if (!conn) { | ||
374 | conn = hci_conn_add(hdev, ACL_LINK, &cp->bdaddr); | ||
375 | if (conn) { | ||
376 | conn->out = 1; | ||
377 | conn->link_mode |= HCI_LM_MASTER; | ||
378 | } else | ||
379 | BT_ERR("No memmory for new connection"); | ||
380 | } | ||
381 | } | ||
382 | |||
383 | hci_dev_unlock(hdev); | ||
384 | } | ||
385 | |||
386 | static void hci_cs_link_ctl(struct hci_dev *hdev, __u16 ocf, __u8 status) | ||
387 | { | ||
388 | BT_DBG("%s ocf 0x%x", hdev->name, ocf); | ||
389 | |||
390 | switch (ocf) { | ||
391 | case OCF_CREATE_CONN: | ||
392 | hci_cs_create_conn(hdev, status); | ||
393 | break; | ||
394 | |||
395 | case OCF_ADD_SCO: | ||
396 | if (status) { | ||
397 | struct hci_conn *acl, *sco; | ||
398 | struct hci_cp_add_sco *cp = hci_sent_cmd_data(hdev, OGF_LINK_CTL, OCF_ADD_SCO); | ||
399 | __u16 handle; | ||
400 | |||
401 | if (!cp) | ||
402 | break; | ||
403 | |||
404 | handle = __le16_to_cpu(cp->handle); | ||
405 | |||
406 | BT_DBG("%s Add SCO error: handle %d status 0x%x", hdev->name, handle, status); | ||
407 | |||
408 | hci_dev_lock(hdev); | ||
409 | |||
410 | acl = hci_conn_hash_lookup_handle(hdev, handle); | ||
411 | if (acl && (sco = acl->link)) { | ||
412 | sco->state = BT_CLOSED; | ||
413 | |||
414 | hci_proto_connect_cfm(sco, status); | ||
415 | hci_conn_del(sco); | ||
416 | } | ||
417 | |||
418 | hci_dev_unlock(hdev); | ||
419 | } | ||
420 | break; | ||
421 | |||
422 | case OCF_INQUIRY: | ||
423 | if (status) { | ||
424 | BT_DBG("%s Inquiry error: status 0x%x", hdev->name, status); | ||
425 | hci_req_complete(hdev, status); | ||
426 | } else { | ||
427 | set_bit(HCI_INQUIRY, &hdev->flags); | ||
428 | } | ||
429 | break; | ||
430 | |||
431 | default: | ||
432 | BT_DBG("%s Command status: ogf LINK_CTL ocf %x status %d", | ||
433 | hdev->name, ocf, status); | ||
434 | break; | ||
435 | } | ||
436 | } | ||
437 | |||
438 | /* Command Status OGF LINK_POLICY */ | ||
439 | static void hci_cs_link_policy(struct hci_dev *hdev, __u16 ocf, __u8 status) | ||
440 | { | ||
441 | BT_DBG("%s ocf 0x%x", hdev->name, ocf); | ||
442 | |||
443 | switch (ocf) { | ||
444 | default: | ||
445 | BT_DBG("%s Command status: ogf HOST_POLICY ocf %x", hdev->name, ocf); | ||
446 | break; | ||
447 | } | ||
448 | } | ||
449 | |||
450 | /* Command Status OGF HOST_CTL */ | ||
451 | static void hci_cs_host_ctl(struct hci_dev *hdev, __u16 ocf, __u8 status) | ||
452 | { | ||
453 | BT_DBG("%s ocf 0x%x", hdev->name, ocf); | ||
454 | |||
455 | switch (ocf) { | ||
456 | default: | ||
457 | BT_DBG("%s Command status: ogf HOST_CTL ocf %x", hdev->name, ocf); | ||
458 | break; | ||
459 | } | ||
460 | } | ||
461 | |||
462 | /* Command Status OGF INFO_PARAM */ | ||
463 | static void hci_cs_info_param(struct hci_dev *hdev, __u16 ocf, __u8 status) | ||
464 | { | ||
465 | BT_DBG("%s: hci_cs_info_param: ocf 0x%x", hdev->name, ocf); | ||
466 | |||
467 | switch (ocf) { | ||
468 | default: | ||
469 | BT_DBG("%s Command status: ogf INFO_PARAM ocf %x", hdev->name, ocf); | ||
470 | break; | ||
471 | } | ||
472 | } | ||
473 | |||
474 | /* Inquiry Complete */ | ||
475 | static inline void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) | ||
476 | { | ||
477 | __u8 status = *((__u8 *) skb->data); | ||
478 | |||
479 | BT_DBG("%s status %d", hdev->name, status); | ||
480 | |||
481 | clear_bit(HCI_INQUIRY, &hdev->flags); | ||
482 | hci_req_complete(hdev, status); | ||
483 | } | ||
484 | |||
485 | /* Inquiry Result */ | ||
486 | static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb) | ||
487 | { | ||
488 | struct inquiry_info *info = (struct inquiry_info *) (skb->data + 1); | ||
489 | int num_rsp = *((__u8 *) skb->data); | ||
490 | |||
491 | BT_DBG("%s num_rsp %d", hdev->name, num_rsp); | ||
492 | |||
493 | hci_dev_lock(hdev); | ||
494 | for (; num_rsp; num_rsp--) { | ||
495 | struct inquiry_data data; | ||
496 | bacpy(&data.bdaddr, &info->bdaddr); | ||
497 | data.pscan_rep_mode = info->pscan_rep_mode; | ||
498 | data.pscan_period_mode = info->pscan_period_mode; | ||
499 | data.pscan_mode = info->pscan_mode; | ||
500 | memcpy(data.dev_class, info->dev_class, 3); | ||
501 | data.clock_offset = info->clock_offset; | ||
502 | data.rssi = 0x00; | ||
503 | info++; | ||
504 | hci_inquiry_cache_update(hdev, &data); | ||
505 | } | ||
506 | hci_dev_unlock(hdev); | ||
507 | } | ||
508 | |||
509 | /* Inquiry Result With RSSI */ | ||
510 | static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct sk_buff *skb) | ||
511 | { | ||
512 | struct inquiry_info_with_rssi *info = (struct inquiry_info_with_rssi *) (skb->data + 1); | ||
513 | int num_rsp = *((__u8 *) skb->data); | ||
514 | |||
515 | BT_DBG("%s num_rsp %d", hdev->name, num_rsp); | ||
516 | |||
517 | hci_dev_lock(hdev); | ||
518 | for (; num_rsp; num_rsp--) { | ||
519 | struct inquiry_data data; | ||
520 | bacpy(&data.bdaddr, &info->bdaddr); | ||
521 | data.pscan_rep_mode = info->pscan_rep_mode; | ||
522 | data.pscan_period_mode = info->pscan_period_mode; | ||
523 | data.pscan_mode = 0x00; | ||
524 | memcpy(data.dev_class, info->dev_class, 3); | ||
525 | data.clock_offset = info->clock_offset; | ||
526 | data.rssi = info->rssi; | ||
527 | info++; | ||
528 | hci_inquiry_cache_update(hdev, &data); | ||
529 | } | ||
530 | hci_dev_unlock(hdev); | ||
531 | } | ||
532 | |||
533 | /* Connect Request */ | ||
534 | static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb) | ||
535 | { | ||
536 | struct hci_ev_conn_request *ev = (struct hci_ev_conn_request *) skb->data; | ||
537 | int mask = hdev->link_mode; | ||
538 | |||
539 | BT_DBG("%s Connection request: %s type 0x%x", hdev->name, | ||
540 | batostr(&ev->bdaddr), ev->link_type); | ||
541 | |||
542 | mask |= hci_proto_connect_ind(hdev, &ev->bdaddr, ev->link_type); | ||
543 | |||
544 | if (mask & HCI_LM_ACCEPT) { | ||
545 | /* Connection accepted */ | ||
546 | struct hci_conn *conn; | ||
547 | struct hci_cp_accept_conn_req cp; | ||
548 | |||
549 | hci_dev_lock(hdev); | ||
550 | conn = hci_conn_hash_lookup_ba(hdev, ev->link_type, &ev->bdaddr); | ||
551 | if (!conn) { | ||
552 | if (!(conn = hci_conn_add(hdev, ev->link_type, &ev->bdaddr))) { | ||
553 | BT_ERR("No memmory for new connection"); | ||
554 | hci_dev_unlock(hdev); | ||
555 | return; | ||
556 | } | ||
557 | } | ||
558 | memcpy(conn->dev_class, ev->dev_class, 3); | ||
559 | conn->state = BT_CONNECT; | ||
560 | hci_dev_unlock(hdev); | ||
561 | |||
562 | bacpy(&cp.bdaddr, &ev->bdaddr); | ||
563 | |||
564 | if (lmp_rswitch_capable(hdev) && (mask & HCI_LM_MASTER)) | ||
565 | cp.role = 0x00; /* Become master */ | ||
566 | else | ||
567 | cp.role = 0x01; /* Remain slave */ | ||
568 | |||
569 | hci_send_cmd(hdev, OGF_LINK_CTL, OCF_ACCEPT_CONN_REQ, sizeof(cp), &cp); | ||
570 | } else { | ||
571 | /* Connection rejected */ | ||
572 | struct hci_cp_reject_conn_req cp; | ||
573 | |||
574 | bacpy(&cp.bdaddr, &ev->bdaddr); | ||
575 | cp.reason = 0x0f; | ||
576 | hci_send_cmd(hdev, OGF_LINK_CTL, OCF_REJECT_CONN_REQ, sizeof(cp), &cp); | ||
577 | } | ||
578 | } | ||
579 | |||
580 | /* Connect Complete */ | ||
581 | static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) | ||
582 | { | ||
583 | struct hci_ev_conn_complete *ev = (struct hci_ev_conn_complete *) skb->data; | ||
584 | struct hci_conn *conn = NULL; | ||
585 | |||
586 | BT_DBG("%s", hdev->name); | ||
587 | |||
588 | hci_dev_lock(hdev); | ||
589 | |||
590 | conn = hci_conn_hash_lookup_ba(hdev, ev->link_type, &ev->bdaddr); | ||
591 | if (!conn) { | ||
592 | hci_dev_unlock(hdev); | ||
593 | return; | ||
594 | } | ||
595 | |||
596 | if (!ev->status) { | ||
597 | conn->handle = __le16_to_cpu(ev->handle); | ||
598 | conn->state = BT_CONNECTED; | ||
599 | |||
600 | if (test_bit(HCI_AUTH, &hdev->flags)) | ||
601 | conn->link_mode |= HCI_LM_AUTH; | ||
602 | |||
603 | if (test_bit(HCI_ENCRYPT, &hdev->flags)) | ||
604 | conn->link_mode |= HCI_LM_ENCRYPT; | ||
605 | |||
606 | /* Set link policy */ | ||
607 | if (conn->type == ACL_LINK && hdev->link_policy) { | ||
608 | struct hci_cp_write_link_policy cp; | ||
609 | cp.handle = ev->handle; | ||
610 | cp.policy = __cpu_to_le16(hdev->link_policy); | ||
611 | hci_send_cmd(hdev, OGF_LINK_POLICY, OCF_WRITE_LINK_POLICY, sizeof(cp), &cp); | ||
612 | } | ||
613 | |||
614 | /* Set packet type for incoming connection */ | ||
615 | if (!conn->out) { | ||
616 | struct hci_cp_change_conn_ptype cp; | ||
617 | cp.handle = ev->handle; | ||
618 | cp.pkt_type = (conn->type == ACL_LINK) ? | ||
619 | __cpu_to_le16(hdev->pkt_type & ACL_PTYPE_MASK): | ||
620 | __cpu_to_le16(hdev->pkt_type & SCO_PTYPE_MASK); | ||
621 | |||
622 | hci_send_cmd(hdev, OGF_LINK_CTL, OCF_CHANGE_CONN_PTYPE, sizeof(cp), &cp); | ||
623 | } | ||
624 | } else | ||
625 | conn->state = BT_CLOSED; | ||
626 | |||
627 | if (conn->type == ACL_LINK) { | ||
628 | struct hci_conn *sco = conn->link; | ||
629 | if (sco) { | ||
630 | if (!ev->status) | ||
631 | hci_add_sco(sco, conn->handle); | ||
632 | else { | ||
633 | hci_proto_connect_cfm(sco, ev->status); | ||
634 | hci_conn_del(sco); | ||
635 | } | ||
636 | } | ||
637 | } | ||
638 | |||
639 | hci_proto_connect_cfm(conn, ev->status); | ||
640 | if (ev->status) | ||
641 | hci_conn_del(conn); | ||
642 | |||
643 | hci_dev_unlock(hdev); | ||
644 | } | ||
645 | |||
646 | /* Disconnect Complete */ | ||
647 | static inline void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) | ||
648 | { | ||
649 | struct hci_ev_disconn_complete *ev = (struct hci_ev_disconn_complete *) skb->data; | ||
650 | struct hci_conn *conn = NULL; | ||
651 | __u16 handle = __le16_to_cpu(ev->handle); | ||
652 | |||
653 | BT_DBG("%s status %d", hdev->name, ev->status); | ||
654 | |||
655 | if (ev->status) | ||
656 | return; | ||
657 | |||
658 | hci_dev_lock(hdev); | ||
659 | |||
660 | conn = hci_conn_hash_lookup_handle(hdev, handle); | ||
661 | if (conn) { | ||
662 | conn->state = BT_CLOSED; | ||
663 | hci_proto_disconn_ind(conn, ev->reason); | ||
664 | hci_conn_del(conn); | ||
665 | } | ||
666 | |||
667 | hci_dev_unlock(hdev); | ||
668 | } | ||
669 | |||
670 | /* Number of completed packets */ | ||
671 | static inline void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *skb) | ||
672 | { | ||
673 | struct hci_ev_num_comp_pkts *ev = (struct hci_ev_num_comp_pkts *) skb->data; | ||
674 | __u16 *ptr; | ||
675 | int i; | ||
676 | |||
677 | skb_pull(skb, sizeof(*ev)); | ||
678 | |||
679 | BT_DBG("%s num_hndl %d", hdev->name, ev->num_hndl); | ||
680 | |||
681 | if (skb->len < ev->num_hndl * 4) { | ||
682 | BT_DBG("%s bad parameters", hdev->name); | ||
683 | return; | ||
684 | } | ||
685 | |||
686 | tasklet_disable(&hdev->tx_task); | ||
687 | |||
688 | for (i = 0, ptr = (__u16 *) skb->data; i < ev->num_hndl; i++) { | ||
689 | struct hci_conn *conn; | ||
690 | __u16 handle, count; | ||
691 | |||
692 | handle = __le16_to_cpu(get_unaligned(ptr++)); | ||
693 | count = __le16_to_cpu(get_unaligned(ptr++)); | ||
694 | |||
695 | conn = hci_conn_hash_lookup_handle(hdev, handle); | ||
696 | if (conn) { | ||
697 | conn->sent -= count; | ||
698 | |||
699 | if (conn->type == SCO_LINK) { | ||
700 | if ((hdev->sco_cnt += count) > hdev->sco_pkts) | ||
701 | hdev->sco_cnt = hdev->sco_pkts; | ||
702 | } else { | ||
703 | if ((hdev->acl_cnt += count) > hdev->acl_pkts) | ||
704 | hdev->acl_cnt = hdev->acl_pkts; | ||
705 | } | ||
706 | } | ||
707 | } | ||
708 | hci_sched_tx(hdev); | ||
709 | |||
710 | tasklet_enable(&hdev->tx_task); | ||
711 | } | ||
712 | |||
713 | /* Role Change */ | ||
714 | static inline void hci_role_change_evt(struct hci_dev *hdev, struct sk_buff *skb) | ||
715 | { | ||
716 | struct hci_ev_role_change *ev = (struct hci_ev_role_change *) skb->data; | ||
717 | struct hci_conn *conn = NULL; | ||
718 | |||
719 | BT_DBG("%s status %d", hdev->name, ev->status); | ||
720 | |||
721 | hci_dev_lock(hdev); | ||
722 | |||
723 | conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr); | ||
724 | if (conn) { | ||
725 | if (!ev->status) { | ||
726 | if (ev->role) | ||
727 | conn->link_mode &= ~HCI_LM_MASTER; | ||
728 | else | ||
729 | conn->link_mode |= HCI_LM_MASTER; | ||
730 | } | ||
731 | |||
732 | clear_bit(HCI_CONN_RSWITCH_PEND, &conn->pend); | ||
733 | |||
734 | hci_role_switch_cfm(conn, ev->status, ev->role); | ||
735 | } | ||
736 | |||
737 | hci_dev_unlock(hdev); | ||
738 | } | ||
739 | |||
740 | /* Authentication Complete */ | ||
741 | static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) | ||
742 | { | ||
743 | struct hci_ev_auth_complete *ev = (struct hci_ev_auth_complete *) skb->data; | ||
744 | struct hci_conn *conn = NULL; | ||
745 | __u16 handle = __le16_to_cpu(ev->handle); | ||
746 | |||
747 | BT_DBG("%s status %d", hdev->name, ev->status); | ||
748 | |||
749 | hci_dev_lock(hdev); | ||
750 | |||
751 | conn = hci_conn_hash_lookup_handle(hdev, handle); | ||
752 | if (conn) { | ||
753 | if (!ev->status) | ||
754 | conn->link_mode |= HCI_LM_AUTH; | ||
755 | |||
756 | clear_bit(HCI_CONN_AUTH_PEND, &conn->pend); | ||
757 | |||
758 | hci_auth_cfm(conn, ev->status); | ||
759 | |||
760 | if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) { | ||
761 | if (!ev->status) { | ||
762 | struct hci_cp_set_conn_encrypt cp; | ||
763 | cp.handle = __cpu_to_le16(conn->handle); | ||
764 | cp.encrypt = 1; | ||
765 | hci_send_cmd(conn->hdev, OGF_LINK_CTL, | ||
766 | OCF_SET_CONN_ENCRYPT, | ||
767 | sizeof(cp), &cp); | ||
768 | } else { | ||
769 | clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend); | ||
770 | hci_encrypt_cfm(conn, ev->status, 0x00); | ||
771 | } | ||
772 | } | ||
773 | } | ||
774 | |||
775 | hci_dev_unlock(hdev); | ||
776 | } | ||
777 | |||
778 | /* Encryption Change */ | ||
779 | static inline void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff *skb) | ||
780 | { | ||
781 | struct hci_ev_encrypt_change *ev = (struct hci_ev_encrypt_change *) skb->data; | ||
782 | struct hci_conn *conn = NULL; | ||
783 | __u16 handle = __le16_to_cpu(ev->handle); | ||
784 | |||
785 | BT_DBG("%s status %d", hdev->name, ev->status); | ||
786 | |||
787 | hci_dev_lock(hdev); | ||
788 | |||
789 | conn = hci_conn_hash_lookup_handle(hdev, handle); | ||
790 | if (conn) { | ||
791 | if (!ev->status) { | ||
792 | if (ev->encrypt) | ||
793 | conn->link_mode |= HCI_LM_ENCRYPT; | ||
794 | else | ||
795 | conn->link_mode &= ~HCI_LM_ENCRYPT; | ||
796 | } | ||
797 | |||
798 | clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend); | ||
799 | |||
800 | hci_encrypt_cfm(conn, ev->status, ev->encrypt); | ||
801 | } | ||
802 | |||
803 | hci_dev_unlock(hdev); | ||
804 | } | ||
805 | |||
806 | /* Change Connection Link Key Complete */ | ||
807 | static inline void hci_change_conn_link_key_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) | ||
808 | { | ||
809 | struct hci_ev_change_conn_link_key_complete *ev = (struct hci_ev_change_conn_link_key_complete *) skb->data; | ||
810 | struct hci_conn *conn = NULL; | ||
811 | __u16 handle = __le16_to_cpu(ev->handle); | ||
812 | |||
813 | BT_DBG("%s status %d", hdev->name, ev->status); | ||
814 | |||
815 | hci_dev_lock(hdev); | ||
816 | |||
817 | conn = hci_conn_hash_lookup_handle(hdev, handle); | ||
818 | if (conn) { | ||
819 | if (!ev->status) | ||
820 | conn->link_mode |= HCI_LM_SECURE; | ||
821 | |||
822 | clear_bit(HCI_CONN_AUTH_PEND, &conn->pend); | ||
823 | |||
824 | hci_key_change_cfm(conn, ev->status); | ||
825 | } | ||
826 | |||
827 | hci_dev_unlock(hdev); | ||
828 | } | ||
829 | |||
830 | /* Pin Code Request*/ | ||
831 | static inline void hci_pin_code_request_evt(struct hci_dev *hdev, struct sk_buff *skb) | ||
832 | { | ||
833 | } | ||
834 | |||
835 | /* Link Key Request */ | ||
836 | static inline void hci_link_key_request_evt(struct hci_dev *hdev, struct sk_buff *skb) | ||
837 | { | ||
838 | } | ||
839 | |||
840 | /* Link Key Notification */ | ||
841 | static inline void hci_link_key_notify_evt(struct hci_dev *hdev, struct sk_buff *skb) | ||
842 | { | ||
843 | } | ||
844 | |||
845 | /* Clock Offset */ | ||
846 | static inline void hci_clock_offset_evt(struct hci_dev *hdev, struct sk_buff *skb) | ||
847 | { | ||
848 | struct hci_ev_clock_offset *ev = (struct hci_ev_clock_offset *) skb->data; | ||
849 | struct hci_conn *conn = NULL; | ||
850 | __u16 handle = __le16_to_cpu(ev->handle); | ||
851 | |||
852 | BT_DBG("%s status %d", hdev->name, ev->status); | ||
853 | |||
854 | hci_dev_lock(hdev); | ||
855 | |||
856 | conn = hci_conn_hash_lookup_handle(hdev, handle); | ||
857 | if (conn && !ev->status) { | ||
858 | struct inquiry_entry *ie; | ||
859 | |||
860 | if ((ie = hci_inquiry_cache_lookup(hdev, &conn->dst))) { | ||
861 | ie->data.clock_offset = ev->clock_offset; | ||
862 | ie->timestamp = jiffies; | ||
863 | } | ||
864 | } | ||
865 | |||
866 | hci_dev_unlock(hdev); | ||
867 | } | ||
868 | |||
869 | void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb) | ||
870 | { | ||
871 | struct hci_event_hdr *hdr = (struct hci_event_hdr *) skb->data; | ||
872 | struct hci_ev_cmd_complete *ec; | ||
873 | struct hci_ev_cmd_status *cs; | ||
874 | u16 opcode, ocf, ogf; | ||
875 | |||
876 | skb_pull(skb, HCI_EVENT_HDR_SIZE); | ||
877 | |||
878 | BT_DBG("%s evt 0x%x", hdev->name, hdr->evt); | ||
879 | |||
880 | switch (hdr->evt) { | ||
881 | case HCI_EV_NUM_COMP_PKTS: | ||
882 | hci_num_comp_pkts_evt(hdev, skb); | ||
883 | break; | ||
884 | |||
885 | case HCI_EV_INQUIRY_COMPLETE: | ||
886 | hci_inquiry_complete_evt(hdev, skb); | ||
887 | break; | ||
888 | |||
889 | case HCI_EV_INQUIRY_RESULT: | ||
890 | hci_inquiry_result_evt(hdev, skb); | ||
891 | break; | ||
892 | |||
893 | case HCI_EV_INQUIRY_RESULT_WITH_RSSI: | ||
894 | hci_inquiry_result_with_rssi_evt(hdev, skb); | ||
895 | break; | ||
896 | |||
897 | case HCI_EV_CONN_REQUEST: | ||
898 | hci_conn_request_evt(hdev, skb); | ||
899 | break; | ||
900 | |||
901 | case HCI_EV_CONN_COMPLETE: | ||
902 | hci_conn_complete_evt(hdev, skb); | ||
903 | break; | ||
904 | |||
905 | case HCI_EV_DISCONN_COMPLETE: | ||
906 | hci_disconn_complete_evt(hdev, skb); | ||
907 | break; | ||
908 | |||
909 | case HCI_EV_ROLE_CHANGE: | ||
910 | hci_role_change_evt(hdev, skb); | ||
911 | break; | ||
912 | |||
913 | case HCI_EV_AUTH_COMPLETE: | ||
914 | hci_auth_complete_evt(hdev, skb); | ||
915 | break; | ||
916 | |||
917 | case HCI_EV_ENCRYPT_CHANGE: | ||
918 | hci_encrypt_change_evt(hdev, skb); | ||
919 | break; | ||
920 | |||
921 | case HCI_EV_CHANGE_CONN_LINK_KEY_COMPLETE: | ||
922 | hci_change_conn_link_key_complete_evt(hdev, skb); | ||
923 | break; | ||
924 | |||
925 | case HCI_EV_PIN_CODE_REQ: | ||
926 | hci_pin_code_request_evt(hdev, skb); | ||
927 | break; | ||
928 | |||
929 | case HCI_EV_LINK_KEY_REQ: | ||
930 | hci_link_key_request_evt(hdev, skb); | ||
931 | break; | ||
932 | |||
933 | case HCI_EV_LINK_KEY_NOTIFY: | ||
934 | hci_link_key_notify_evt(hdev, skb); | ||
935 | break; | ||
936 | |||
937 | case HCI_EV_CLOCK_OFFSET: | ||
938 | hci_clock_offset_evt(hdev, skb); | ||
939 | break; | ||
940 | |||
941 | case HCI_EV_CMD_STATUS: | ||
942 | cs = (struct hci_ev_cmd_status *) skb->data; | ||
943 | skb_pull(skb, sizeof(cs)); | ||
944 | |||
945 | opcode = __le16_to_cpu(cs->opcode); | ||
946 | ogf = hci_opcode_ogf(opcode); | ||
947 | ocf = hci_opcode_ocf(opcode); | ||
948 | |||
949 | switch (ogf) { | ||
950 | case OGF_INFO_PARAM: | ||
951 | hci_cs_info_param(hdev, ocf, cs->status); | ||
952 | break; | ||
953 | |||
954 | case OGF_HOST_CTL: | ||
955 | hci_cs_host_ctl(hdev, ocf, cs->status); | ||
956 | break; | ||
957 | |||
958 | case OGF_LINK_CTL: | ||
959 | hci_cs_link_ctl(hdev, ocf, cs->status); | ||
960 | break; | ||
961 | |||
962 | case OGF_LINK_POLICY: | ||
963 | hci_cs_link_policy(hdev, ocf, cs->status); | ||
964 | break; | ||
965 | |||
966 | default: | ||
967 | BT_DBG("%s Command Status OGF %x", hdev->name, ogf); | ||
968 | break; | ||
969 | } | ||
970 | |||
971 | if (cs->ncmd) { | ||
972 | atomic_set(&hdev->cmd_cnt, 1); | ||
973 | if (!skb_queue_empty(&hdev->cmd_q)) | ||
974 | hci_sched_cmd(hdev); | ||
975 | } | ||
976 | break; | ||
977 | |||
978 | case HCI_EV_CMD_COMPLETE: | ||
979 | ec = (struct hci_ev_cmd_complete *) skb->data; | ||
980 | skb_pull(skb, sizeof(*ec)); | ||
981 | |||
982 | opcode = __le16_to_cpu(ec->opcode); | ||
983 | ogf = hci_opcode_ogf(opcode); | ||
984 | ocf = hci_opcode_ocf(opcode); | ||
985 | |||
986 | switch (ogf) { | ||
987 | case OGF_INFO_PARAM: | ||
988 | hci_cc_info_param(hdev, ocf, skb); | ||
989 | break; | ||
990 | |||
991 | case OGF_HOST_CTL: | ||
992 | hci_cc_host_ctl(hdev, ocf, skb); | ||
993 | break; | ||
994 | |||
995 | case OGF_LINK_CTL: | ||
996 | hci_cc_link_ctl(hdev, ocf, skb); | ||
997 | break; | ||
998 | |||
999 | case OGF_LINK_POLICY: | ||
1000 | hci_cc_link_policy(hdev, ocf, skb); | ||
1001 | break; | ||
1002 | |||
1003 | default: | ||
1004 | BT_DBG("%s Command Completed OGF %x", hdev->name, ogf); | ||
1005 | break; | ||
1006 | } | ||
1007 | |||
1008 | if (ec->ncmd) { | ||
1009 | atomic_set(&hdev->cmd_cnt, 1); | ||
1010 | if (!skb_queue_empty(&hdev->cmd_q)) | ||
1011 | hci_sched_cmd(hdev); | ||
1012 | } | ||
1013 | break; | ||
1014 | } | ||
1015 | |||
1016 | kfree_skb(skb); | ||
1017 | hdev->stat.evt_rx++; | ||
1018 | } | ||
1019 | |||
1020 | /* Generate internal stack event */ | ||
1021 | void hci_si_event(struct hci_dev *hdev, int type, int dlen, void *data) | ||
1022 | { | ||
1023 | struct hci_event_hdr *hdr; | ||
1024 | struct hci_ev_stack_internal *ev; | ||
1025 | struct sk_buff *skb; | ||
1026 | |||
1027 | skb = bt_skb_alloc(HCI_EVENT_HDR_SIZE + sizeof(*ev) + dlen, GFP_ATOMIC); | ||
1028 | if (!skb) | ||
1029 | return; | ||
1030 | |||
1031 | hdr = (void *) skb_put(skb, HCI_EVENT_HDR_SIZE); | ||
1032 | hdr->evt = HCI_EV_STACK_INTERNAL; | ||
1033 | hdr->plen = sizeof(*ev) + dlen; | ||
1034 | |||
1035 | ev = (void *) skb_put(skb, sizeof(*ev) + dlen); | ||
1036 | ev->type = type; | ||
1037 | memcpy(ev->data, data, dlen); | ||
1038 | |||
1039 | skb->pkt_type = HCI_EVENT_PKT; | ||
1040 | skb->dev = (void *) hdev; | ||
1041 | hci_send_to_sock(hdev, skb); | ||
1042 | kfree_skb(skb); | ||
1043 | } | ||
1044 | EXPORT_SYMBOL(hci_si_event); | ||