aboutsummaryrefslogtreecommitdiffstats
path: root/net/bluetooth/hidp
diff options
context:
space:
mode:
Diffstat (limited to 'net/bluetooth/hidp')
-rw-r--r--net/bluetooth/hidp/Kconfig12
-rw-r--r--net/bluetooth/hidp/Makefile7
-rw-r--r--net/bluetooth/hidp/core.c772
-rw-r--r--net/bluetooth/hidp/hidp.h167
-rw-r--r--net/bluetooth/hidp/sock.c232
5 files changed, 1190 insertions, 0 deletions
diff --git a/net/bluetooth/hidp/Kconfig b/net/bluetooth/hidp/Kconfig
new file mode 100644
index 000000000000..4e958f7d9418
--- /dev/null
+++ b/net/bluetooth/hidp/Kconfig
@@ -0,0 +1,12 @@
1config BT_HIDP
2 tristate "HIDP protocol support"
3 depends on BT && BT_L2CAP
4 select INPUT
5 help
6 HIDP (Human Interface Device Protocol) is a transport layer
7 for HID reports. HIDP is required for the Bluetooth Human
8 Interface Device Profile.
9
10 Say Y here to compile HIDP support into the kernel or say M to
11 compile it as module (hidp).
12
diff --git a/net/bluetooth/hidp/Makefile b/net/bluetooth/hidp/Makefile
new file mode 100644
index 000000000000..a9ee115696ae
--- /dev/null
+++ b/net/bluetooth/hidp/Makefile
@@ -0,0 +1,7 @@
1#
2# Makefile for the Linux Bluetooth HIDP layer
3#
4
5obj-$(CONFIG_BT_HIDP) += hidp.o
6
7hidp-objs := core.o sock.o
diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c
new file mode 100644
index 000000000000..2cf98ceabcc7
--- /dev/null
+++ b/net/bluetooth/hidp/core.c
@@ -0,0 +1,772 @@
1/*
2 HIDP implementation for Linux Bluetooth stack (BlueZ).
3 Copyright (C) 2003-2004 Marcel Holtmann <marcel@holtmann.org>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License version 2 as
7 published by the Free Software Foundation;
8
9 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
10 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
11 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
12 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
13 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
18 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
19 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
20 SOFTWARE IS DISCLAIMED.
21*/
22
23#include <linux/config.h>
24#include <linux/module.h>
25
26#include <linux/types.h>
27#include <linux/errno.h>
28#include <linux/kernel.h>
29#include <linux/major.h>
30#include <linux/sched.h>
31#include <linux/slab.h>
32#include <linux/poll.h>
33#include <linux/fcntl.h>
34#include <linux/skbuff.h>
35#include <linux/socket.h>
36#include <linux/ioctl.h>
37#include <linux/file.h>
38#include <linux/init.h>
39#include <linux/wait.h>
40#include <net/sock.h>
41
42#include <linux/input.h>
43
44#include <net/bluetooth/bluetooth.h>
45#include <net/bluetooth/l2cap.h>
46
47#include "hidp.h"
48
49#ifndef CONFIG_BT_HIDP_DEBUG
50#undef BT_DBG
51#define BT_DBG(D...)
52#endif
53
54#define VERSION "1.1"
55
56static DECLARE_RWSEM(hidp_session_sem);
57static LIST_HEAD(hidp_session_list);
58
59static unsigned char hidp_keycode[256] = {
60 0, 0, 0, 0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38,
61 50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44, 2, 3,
62 4, 5, 6, 7, 8, 9, 10, 11, 28, 1, 14, 15, 57, 12, 13, 26,
63 27, 43, 43, 39, 40, 41, 51, 52, 53, 58, 59, 60, 61, 62, 63, 64,
64 65, 66, 67, 68, 87, 88, 99, 70,119,110,102,104,111,107,109,106,
65 105,108,103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71,
66 72, 73, 82, 83, 86,127,116,117,183,184,185,186,187,188,189,190,
67 191,192,193,194,134,138,130,132,128,129,131,137,133,135,136,113,
68 115,114, 0, 0, 0,121, 0, 89, 93,124, 92, 94, 95, 0, 0, 0,
69 122,123, 90, 91, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
70 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
71 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
72 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
73 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
74 29, 42, 56,125, 97, 54,100,126,164,166,165,163,161,115,114,113,
75 150,158,159,128,136,177,178,176,142,152,173,140
76};
77
78static unsigned char hidp_mkeyspat[] = { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 };
79
80static struct hidp_session *__hidp_get_session(bdaddr_t *bdaddr)
81{
82 struct hidp_session *session;
83 struct list_head *p;
84
85 BT_DBG("");
86
87 list_for_each(p, &hidp_session_list) {
88 session = list_entry(p, struct hidp_session, list);
89 if (!bacmp(bdaddr, &session->bdaddr))
90 return session;
91 }
92 return NULL;
93}
94
95static void __hidp_link_session(struct hidp_session *session)
96{
97 __module_get(THIS_MODULE);
98 list_add(&session->list, &hidp_session_list);
99}
100
101static void __hidp_unlink_session(struct hidp_session *session)
102{
103 list_del(&session->list);
104 module_put(THIS_MODULE);
105}
106
107static void __hidp_copy_session(struct hidp_session *session, struct hidp_conninfo *ci)
108{
109 bacpy(&ci->bdaddr, &session->bdaddr);
110
111 ci->flags = session->flags;
112 ci->state = session->state;
113
114 ci->vendor = 0x0000;
115 ci->product = 0x0000;
116 ci->version = 0x0000;
117 memset(ci->name, 0, 128);
118
119 if (session->input) {
120 ci->vendor = session->input->id.vendor;
121 ci->product = session->input->id.product;
122 ci->version = session->input->id.version;
123 if (session->input->name)
124 strncpy(ci->name, session->input->name, 128);
125 else
126 strncpy(ci->name, "HID Boot Device", 128);
127 }
128}
129
130static int hidp_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
131{
132 struct hidp_session *session = dev->private;
133 struct sk_buff *skb;
134 unsigned char newleds;
135
136 BT_DBG("input %p type %d code %d value %d", dev, type, code, value);
137
138 if (type != EV_LED)
139 return -1;
140
141 newleds = (!!test_bit(LED_KANA, dev->led) << 3) |
142 (!!test_bit(LED_COMPOSE, dev->led) << 3) |
143 (!!test_bit(LED_SCROLLL, dev->led) << 2) |
144 (!!test_bit(LED_CAPSL, dev->led) << 1) |
145 (!!test_bit(LED_NUML, dev->led));
146
147 if (session->leds == newleds)
148 return 0;
149
150 session->leds = newleds;
151
152 if (!(skb = alloc_skb(3, GFP_ATOMIC))) {
153 BT_ERR("Can't allocate memory for new frame");
154 return -ENOMEM;
155 }
156
157 *skb_put(skb, 1) = HIDP_TRANS_DATA | HIDP_DATA_RTYPE_OUPUT;
158 *skb_put(skb, 1) = 0x01;
159 *skb_put(skb, 1) = newleds;
160
161 skb_queue_tail(&session->intr_transmit, skb);
162
163 hidp_schedule(session);
164
165 return 0;
166}
167
168static void hidp_input_report(struct hidp_session *session, struct sk_buff *skb)
169{
170 struct input_dev *dev = session->input;
171 unsigned char *keys = session->keys;
172 unsigned char *udata = skb->data + 1;
173 signed char *sdata = skb->data + 1;
174 int i, size = skb->len - 1;
175
176 switch (skb->data[0]) {
177 case 0x01: /* Keyboard report */
178 for (i = 0; i < 8; i++)
179 input_report_key(dev, hidp_keycode[i + 224], (udata[0] >> i) & 1);
180
181 /* If all the key codes have been set to 0x01, it means
182 * too many keys were pressed at the same time. */
183 if (!memcmp(udata + 2, hidp_mkeyspat, 6))
184 break;
185
186 for (i = 2; i < 8; i++) {
187 if (keys[i] > 3 && memscan(udata + 2, keys[i], 6) == udata + 8) {
188 if (hidp_keycode[keys[i]])
189 input_report_key(dev, hidp_keycode[keys[i]], 0);
190 else
191 BT_ERR("Unknown key (scancode %#x) released.", keys[i]);
192 }
193
194 if (udata[i] > 3 && memscan(keys + 2, udata[i], 6) == keys + 8) {
195 if (hidp_keycode[udata[i]])
196 input_report_key(dev, hidp_keycode[udata[i]], 1);
197 else
198 BT_ERR("Unknown key (scancode %#x) pressed.", udata[i]);
199 }
200 }
201
202 memcpy(keys, udata, 8);
203 break;
204
205 case 0x02: /* Mouse report */
206 input_report_key(dev, BTN_LEFT, sdata[0] & 0x01);
207 input_report_key(dev, BTN_RIGHT, sdata[0] & 0x02);
208 input_report_key(dev, BTN_MIDDLE, sdata[0] & 0x04);
209 input_report_key(dev, BTN_SIDE, sdata[0] & 0x08);
210 input_report_key(dev, BTN_EXTRA, sdata[0] & 0x10);
211
212 input_report_rel(dev, REL_X, sdata[1]);
213 input_report_rel(dev, REL_Y, sdata[2]);
214
215 if (size > 3)
216 input_report_rel(dev, REL_WHEEL, sdata[3]);
217 break;
218 }
219
220 input_sync(dev);
221}
222
223static void hidp_idle_timeout(unsigned long arg)
224{
225 struct hidp_session *session = (struct hidp_session *) arg;
226
227 atomic_inc(&session->terminate);
228 hidp_schedule(session);
229}
230
231static inline void hidp_set_timer(struct hidp_session *session)
232{
233 if (session->idle_to > 0)
234 mod_timer(&session->timer, jiffies + HZ * session->idle_to);
235}
236
237static inline void hidp_del_timer(struct hidp_session *session)
238{
239 if (session->idle_to > 0)
240 del_timer(&session->timer);
241}
242
243static int __hidp_send_ctrl_message(struct hidp_session *session,
244 unsigned char hdr, unsigned char *data, int size)
245{
246 struct sk_buff *skb;
247
248 BT_DBG("session %p data %p size %d", session, data, size);
249
250 if (!(skb = alloc_skb(size + 1, GFP_ATOMIC))) {
251 BT_ERR("Can't allocate memory for new frame");
252 return -ENOMEM;
253 }
254
255 *skb_put(skb, 1) = hdr;
256 if (data && size > 0)
257 memcpy(skb_put(skb, size), data, size);
258
259 skb_queue_tail(&session->ctrl_transmit, skb);
260
261 return 0;
262}
263
264static int inline hidp_send_ctrl_message(struct hidp_session *session,
265 unsigned char hdr, unsigned char *data, int size)
266{
267 int err;
268
269 err = __hidp_send_ctrl_message(session, hdr, data, size);
270
271 hidp_schedule(session);
272
273 return err;
274}
275
276static inline void hidp_process_handshake(struct hidp_session *session, unsigned char param)
277{
278 BT_DBG("session %p param 0x%02x", session, param);
279
280 switch (param) {
281 case HIDP_HSHK_SUCCESSFUL:
282 /* FIXME: Call into SET_ GET_ handlers here */
283 break;
284
285 case HIDP_HSHK_NOT_READY:
286 case HIDP_HSHK_ERR_INVALID_REPORT_ID:
287 case HIDP_HSHK_ERR_UNSUPPORTED_REQUEST:
288 case HIDP_HSHK_ERR_INVALID_PARAMETER:
289 /* FIXME: Call into SET_ GET_ handlers here */
290 break;
291
292 case HIDP_HSHK_ERR_UNKNOWN:
293 break;
294
295 case HIDP_HSHK_ERR_FATAL:
296 /* Device requests a reboot, as this is the only way this error
297 * can be recovered. */
298 __hidp_send_ctrl_message(session,
299 HIDP_TRANS_HID_CONTROL | HIDP_CTRL_SOFT_RESET, NULL, 0);
300 break;
301
302 default:
303 __hidp_send_ctrl_message(session,
304 HIDP_TRANS_HANDSHAKE | HIDP_HSHK_ERR_INVALID_PARAMETER, NULL, 0);
305 break;
306 }
307}
308
309static inline void hidp_process_hid_control(struct hidp_session *session, unsigned char param)
310{
311 BT_DBG("session %p param 0x%02x", session, param);
312
313 switch (param) {
314 case HIDP_CTRL_NOP:
315 break;
316
317 case HIDP_CTRL_VIRTUAL_CABLE_UNPLUG:
318 /* Flush the transmit queues */
319 skb_queue_purge(&session->ctrl_transmit);
320 skb_queue_purge(&session->intr_transmit);
321
322 /* Kill session thread */
323 atomic_inc(&session->terminate);
324 break;
325
326 case HIDP_CTRL_HARD_RESET:
327 case HIDP_CTRL_SOFT_RESET:
328 case HIDP_CTRL_SUSPEND:
329 case HIDP_CTRL_EXIT_SUSPEND:
330 /* FIXME: We have to parse these and return no error */
331 break;
332
333 default:
334 __hidp_send_ctrl_message(session,
335 HIDP_TRANS_HANDSHAKE | HIDP_HSHK_ERR_INVALID_PARAMETER, NULL, 0);
336 break;
337 }
338}
339
340static inline void hidp_process_data(struct hidp_session *session, struct sk_buff *skb, unsigned char param)
341{
342 BT_DBG("session %p skb %p len %d param 0x%02x", session, skb, skb->len, param);
343
344 switch (param) {
345 case HIDP_DATA_RTYPE_INPUT:
346 hidp_set_timer(session);
347
348 if (session->input)
349 hidp_input_report(session, skb);
350 break;
351
352 case HIDP_DATA_RTYPE_OTHER:
353 case HIDP_DATA_RTYPE_OUPUT:
354 case HIDP_DATA_RTYPE_FEATURE:
355 break;
356
357 default:
358 __hidp_send_ctrl_message(session,
359 HIDP_TRANS_HANDSHAKE | HIDP_HSHK_ERR_INVALID_PARAMETER, NULL, 0);
360 }
361}
362
363static inline void hidp_recv_ctrl_frame(struct hidp_session *session, struct sk_buff *skb)
364{
365 unsigned char hdr, type, param;
366
367 BT_DBG("session %p skb %p len %d", session, skb, skb->len);
368
369 hdr = skb->data[0];
370 skb_pull(skb, 1);
371
372 type = hdr & HIDP_HEADER_TRANS_MASK;
373 param = hdr & HIDP_HEADER_PARAM_MASK;
374
375 switch (type) {
376 case HIDP_TRANS_HANDSHAKE:
377 hidp_process_handshake(session, param);
378 break;
379
380 case HIDP_TRANS_HID_CONTROL:
381 hidp_process_hid_control(session, param);
382 break;
383
384 case HIDP_TRANS_DATA:
385 hidp_process_data(session, skb, param);
386 break;
387
388 default:
389 __hidp_send_ctrl_message(session,
390 HIDP_TRANS_HANDSHAKE | HIDP_HSHK_ERR_UNSUPPORTED_REQUEST, NULL, 0);
391 break;
392 }
393
394 kfree_skb(skb);
395}
396
397static inline void hidp_recv_intr_frame(struct hidp_session *session, struct sk_buff *skb)
398{
399 unsigned char hdr;
400
401 BT_DBG("session %p skb %p len %d", session, skb, skb->len);
402
403 hdr = skb->data[0];
404 skb_pull(skb, 1);
405
406 if (hdr == (HIDP_TRANS_DATA | HIDP_DATA_RTYPE_INPUT)) {
407 hidp_set_timer(session);
408 if (session->input)
409 hidp_input_report(session, skb);
410 } else {
411 BT_DBG("Unsupported protocol header 0x%02x", hdr);
412 }
413
414 kfree_skb(skb);
415}
416
417static int hidp_send_frame(struct socket *sock, unsigned char *data, int len)
418{
419 struct kvec iv = { data, len };
420 struct msghdr msg;
421
422 BT_DBG("sock %p data %p len %d", sock, data, len);
423
424 if (!len)
425 return 0;
426
427 memset(&msg, 0, sizeof(msg));
428
429 return kernel_sendmsg(sock, &msg, &iv, 1, len);
430}
431
432static int hidp_process_transmit(struct hidp_session *session)
433{
434 struct sk_buff *skb;
435
436 BT_DBG("session %p", session);
437
438 while ((skb = skb_dequeue(&session->ctrl_transmit))) {
439 if (hidp_send_frame(session->ctrl_sock, skb->data, skb->len) < 0) {
440 skb_queue_head(&session->ctrl_transmit, skb);
441 break;
442 }
443
444 hidp_set_timer(session);
445 kfree_skb(skb);
446 }
447
448 while ((skb = skb_dequeue(&session->intr_transmit))) {
449 if (hidp_send_frame(session->intr_sock, skb->data, skb->len) < 0) {
450 skb_queue_head(&session->intr_transmit, skb);
451 break;
452 }
453
454 hidp_set_timer(session);
455 kfree_skb(skb);
456 }
457
458 return skb_queue_len(&session->ctrl_transmit) +
459 skb_queue_len(&session->intr_transmit);
460}
461
462static int hidp_session(void *arg)
463{
464 struct hidp_session *session = arg;
465 struct sock *ctrl_sk = session->ctrl_sock->sk;
466 struct sock *intr_sk = session->intr_sock->sk;
467 struct sk_buff *skb;
468 int vendor = 0x0000, product = 0x0000;
469 wait_queue_t ctrl_wait, intr_wait;
470
471 BT_DBG("session %p", session);
472
473 if (session->input) {
474 vendor = session->input->id.vendor;
475 product = session->input->id.product;
476 }
477
478 daemonize("khidpd_%04x%04x", vendor, product);
479 set_user_nice(current, -15);
480 current->flags |= PF_NOFREEZE;
481
482 init_waitqueue_entry(&ctrl_wait, current);
483 init_waitqueue_entry(&intr_wait, current);
484 add_wait_queue(ctrl_sk->sk_sleep, &ctrl_wait);
485 add_wait_queue(intr_sk->sk_sleep, &intr_wait);
486 while (!atomic_read(&session->terminate)) {
487 set_current_state(TASK_INTERRUPTIBLE);
488
489 if (ctrl_sk->sk_state != BT_CONNECTED || intr_sk->sk_state != BT_CONNECTED)
490 break;
491
492 while ((skb = skb_dequeue(&ctrl_sk->sk_receive_queue))) {
493 skb_orphan(skb);
494 hidp_recv_ctrl_frame(session, skb);
495 }
496
497 while ((skb = skb_dequeue(&intr_sk->sk_receive_queue))) {
498 skb_orphan(skb);
499 hidp_recv_intr_frame(session, skb);
500 }
501
502 hidp_process_transmit(session);
503
504 schedule();
505 }
506 set_current_state(TASK_RUNNING);
507 remove_wait_queue(intr_sk->sk_sleep, &intr_wait);
508 remove_wait_queue(ctrl_sk->sk_sleep, &ctrl_wait);
509
510 down_write(&hidp_session_sem);
511
512 hidp_del_timer(session);
513
514 if (intr_sk->sk_state != BT_CONNECTED)
515 wait_event_timeout(*(ctrl_sk->sk_sleep), (ctrl_sk->sk_state == BT_CLOSED), HZ);
516
517 fput(session->ctrl_sock->file);
518
519 wait_event_timeout(*(intr_sk->sk_sleep), (intr_sk->sk_state == BT_CLOSED), HZ);
520
521 fput(session->intr_sock->file);
522
523 __hidp_unlink_session(session);
524
525 if (session->input) {
526 input_unregister_device(session->input);
527 kfree(session->input);
528 }
529
530 up_write(&hidp_session_sem);
531
532 kfree(session);
533 return 0;
534}
535
536static inline void hidp_setup_input(struct hidp_session *session, struct hidp_connadd_req *req)
537{
538 struct input_dev *input = session->input;
539 int i;
540
541 input->private = session;
542
543 input->id.bustype = BUS_BLUETOOTH;
544 input->id.vendor = req->vendor;
545 input->id.product = req->product;
546 input->id.version = req->version;
547
548 if (req->subclass & 0x40) {
549 set_bit(EV_KEY, input->evbit);
550 set_bit(EV_LED, input->evbit);
551 set_bit(EV_REP, input->evbit);
552
553 set_bit(LED_NUML, input->ledbit);
554 set_bit(LED_CAPSL, input->ledbit);
555 set_bit(LED_SCROLLL, input->ledbit);
556 set_bit(LED_COMPOSE, input->ledbit);
557 set_bit(LED_KANA, input->ledbit);
558
559 for (i = 0; i < sizeof(hidp_keycode); i++)
560 set_bit(hidp_keycode[i], input->keybit);
561 clear_bit(0, input->keybit);
562 }
563
564 if (req->subclass & 0x80) {
565 input->evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
566 input->keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE);
567 input->relbit[0] = BIT(REL_X) | BIT(REL_Y);
568 input->keybit[LONG(BTN_MOUSE)] |= BIT(BTN_SIDE) | BIT(BTN_EXTRA);
569 input->relbit[0] |= BIT(REL_WHEEL);
570 }
571
572 input->event = hidp_input_event;
573
574 input_register_device(input);
575}
576
577int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, struct socket *intr_sock)
578{
579 struct hidp_session *session, *s;
580 int err;
581
582 BT_DBG("");
583
584 if (bacmp(&bt_sk(ctrl_sock->sk)->src, &bt_sk(intr_sock->sk)->src) ||
585 bacmp(&bt_sk(ctrl_sock->sk)->dst, &bt_sk(intr_sock->sk)->dst))
586 return -ENOTUNIQ;
587
588 session = kmalloc(sizeof(struct hidp_session), GFP_KERNEL);
589 if (!session)
590 return -ENOMEM;
591 memset(session, 0, sizeof(struct hidp_session));
592
593 session->input = kmalloc(sizeof(struct input_dev), GFP_KERNEL);
594 if (!session->input) {
595 kfree(session);
596 return -ENOMEM;
597 }
598 memset(session->input, 0, sizeof(struct input_dev));
599
600 down_write(&hidp_session_sem);
601
602 s = __hidp_get_session(&bt_sk(ctrl_sock->sk)->dst);
603 if (s && s->state == BT_CONNECTED) {
604 err = -EEXIST;
605 goto failed;
606 }
607
608 bacpy(&session->bdaddr, &bt_sk(ctrl_sock->sk)->dst);
609
610 session->ctrl_mtu = min_t(uint, l2cap_pi(ctrl_sock->sk)->omtu, l2cap_pi(ctrl_sock->sk)->imtu);
611 session->intr_mtu = min_t(uint, l2cap_pi(intr_sock->sk)->omtu, l2cap_pi(intr_sock->sk)->imtu);
612
613 BT_DBG("ctrl mtu %d intr mtu %d", session->ctrl_mtu, session->intr_mtu);
614
615 session->ctrl_sock = ctrl_sock;
616 session->intr_sock = intr_sock;
617 session->state = BT_CONNECTED;
618
619 init_timer(&session->timer);
620
621 session->timer.function = hidp_idle_timeout;
622 session->timer.data = (unsigned long) session;
623
624 skb_queue_head_init(&session->ctrl_transmit);
625 skb_queue_head_init(&session->intr_transmit);
626
627 session->flags = req->flags & (1 << HIDP_BLUETOOTH_VENDOR_ID);
628 session->idle_to = req->idle_to;
629
630 if (session->input)
631 hidp_setup_input(session, req);
632
633 __hidp_link_session(session);
634
635 hidp_set_timer(session);
636
637 err = kernel_thread(hidp_session, session, CLONE_KERNEL);
638 if (err < 0)
639 goto unlink;
640
641 if (session->input) {
642 hidp_send_ctrl_message(session,
643 HIDP_TRANS_SET_PROTOCOL | HIDP_PROTO_BOOT, NULL, 0);
644 session->flags |= (1 << HIDP_BOOT_PROTOCOL_MODE);
645
646 session->leds = 0xff;
647 hidp_input_event(session->input, EV_LED, 0, 0);
648 }
649
650 up_write(&hidp_session_sem);
651 return 0;
652
653unlink:
654 hidp_del_timer(session);
655
656 __hidp_unlink_session(session);
657
658 if (session->input)
659 input_unregister_device(session->input);
660
661failed:
662 up_write(&hidp_session_sem);
663
664 if (session->input)
665 kfree(session->input);
666
667 kfree(session);
668 return err;
669}
670
671int hidp_del_connection(struct hidp_conndel_req *req)
672{
673 struct hidp_session *session;
674 int err = 0;
675
676 BT_DBG("");
677
678 down_read(&hidp_session_sem);
679
680 session = __hidp_get_session(&req->bdaddr);
681 if (session) {
682 if (req->flags & (1 << HIDP_VIRTUAL_CABLE_UNPLUG)) {
683 hidp_send_ctrl_message(session,
684 HIDP_TRANS_HID_CONTROL | HIDP_CTRL_VIRTUAL_CABLE_UNPLUG, NULL, 0);
685 } else {
686 /* Flush the transmit queues */
687 skb_queue_purge(&session->ctrl_transmit);
688 skb_queue_purge(&session->intr_transmit);
689
690 /* Kill session thread */
691 atomic_inc(&session->terminate);
692 hidp_schedule(session);
693 }
694 } else
695 err = -ENOENT;
696
697 up_read(&hidp_session_sem);
698 return err;
699}
700
701int hidp_get_connlist(struct hidp_connlist_req *req)
702{
703 struct list_head *p;
704 int err = 0, n = 0;
705
706 BT_DBG("");
707
708 down_read(&hidp_session_sem);
709
710 list_for_each(p, &hidp_session_list) {
711 struct hidp_session *session;
712 struct hidp_conninfo ci;
713
714 session = list_entry(p, struct hidp_session, list);
715
716 __hidp_copy_session(session, &ci);
717
718 if (copy_to_user(req->ci, &ci, sizeof(ci))) {
719 err = -EFAULT;
720 break;
721 }
722
723 if (++n >= req->cnum)
724 break;
725
726 req->ci++;
727 }
728 req->cnum = n;
729
730 up_read(&hidp_session_sem);
731 return err;
732}
733
734int hidp_get_conninfo(struct hidp_conninfo *ci)
735{
736 struct hidp_session *session;
737 int err = 0;
738
739 down_read(&hidp_session_sem);
740
741 session = __hidp_get_session(&ci->bdaddr);
742 if (session)
743 __hidp_copy_session(session, ci);
744 else
745 err = -ENOENT;
746
747 up_read(&hidp_session_sem);
748 return err;
749}
750
751static int __init hidp_init(void)
752{
753 l2cap_load();
754
755 BT_INFO("HIDP (Human Interface Emulation) ver %s", VERSION);
756
757 return hidp_init_sockets();
758}
759
760static void __exit hidp_exit(void)
761{
762 hidp_cleanup_sockets();
763}
764
765module_init(hidp_init);
766module_exit(hidp_exit);
767
768MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
769MODULE_DESCRIPTION("Bluetooth HIDP ver " VERSION);
770MODULE_VERSION(VERSION);
771MODULE_LICENSE("GPL");
772MODULE_ALIAS("bt-proto-6");
diff --git a/net/bluetooth/hidp/hidp.h b/net/bluetooth/hidp/hidp.h
new file mode 100644
index 000000000000..c2775f587d2e
--- /dev/null
+++ b/net/bluetooth/hidp/hidp.h
@@ -0,0 +1,167 @@
1/*
2 HIDP implementation for Linux Bluetooth stack (BlueZ).
3 Copyright (C) 2003-2004 Marcel Holtmann <marcel@holtmann.org>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License version 2 as
7 published by the Free Software Foundation;
8
9 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
10 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
11 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
12 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
13 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
18 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
19 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
20 SOFTWARE IS DISCLAIMED.
21*/
22
23#ifndef __HIDP_H
24#define __HIDP_H
25
26#include <linux/types.h>
27#include <net/bluetooth/bluetooth.h>
28
29/* HIDP header masks */
30#define HIDP_HEADER_TRANS_MASK 0xf0
31#define HIDP_HEADER_PARAM_MASK 0x0f
32
33/* HIDP transaction types */
34#define HIDP_TRANS_HANDSHAKE 0x00
35#define HIDP_TRANS_HID_CONTROL 0x10
36#define HIDP_TRANS_GET_REPORT 0x40
37#define HIDP_TRANS_SET_REPORT 0x50
38#define HIDP_TRANS_GET_PROTOCOL 0x60
39#define HIDP_TRANS_SET_PROTOCOL 0x70
40#define HIDP_TRANS_GET_IDLE 0x80
41#define HIDP_TRANS_SET_IDLE 0x90
42#define HIDP_TRANS_DATA 0xa0
43#define HIDP_TRANS_DATC 0xb0
44
45/* HIDP handshake results */
46#define HIDP_HSHK_SUCCESSFUL 0x00
47#define HIDP_HSHK_NOT_READY 0x01
48#define HIDP_HSHK_ERR_INVALID_REPORT_ID 0x02
49#define HIDP_HSHK_ERR_UNSUPPORTED_REQUEST 0x03
50#define HIDP_HSHK_ERR_INVALID_PARAMETER 0x04
51#define HIDP_HSHK_ERR_UNKNOWN 0x0e
52#define HIDP_HSHK_ERR_FATAL 0x0f
53
54/* HIDP control operation parameters */
55#define HIDP_CTRL_NOP 0x00
56#define HIDP_CTRL_HARD_RESET 0x01
57#define HIDP_CTRL_SOFT_RESET 0x02
58#define HIDP_CTRL_SUSPEND 0x03
59#define HIDP_CTRL_EXIT_SUSPEND 0x04
60#define HIDP_CTRL_VIRTUAL_CABLE_UNPLUG 0x05
61
62/* HIDP data transaction headers */
63#define HIDP_DATA_RTYPE_MASK 0x03
64#define HIDP_DATA_RSRVD_MASK 0x0c
65#define HIDP_DATA_RTYPE_OTHER 0x00
66#define HIDP_DATA_RTYPE_INPUT 0x01
67#define HIDP_DATA_RTYPE_OUPUT 0x02
68#define HIDP_DATA_RTYPE_FEATURE 0x03
69
70/* HIDP protocol header parameters */
71#define HIDP_PROTO_BOOT 0x00
72#define HIDP_PROTO_REPORT 0x01
73
74/* HIDP ioctl defines */
75#define HIDPCONNADD _IOW('H', 200, int)
76#define HIDPCONNDEL _IOW('H', 201, int)
77#define HIDPGETCONNLIST _IOR('H', 210, int)
78#define HIDPGETCONNINFO _IOR('H', 211, int)
79
80#define HIDP_VIRTUAL_CABLE_UNPLUG 0
81#define HIDP_BOOT_PROTOCOL_MODE 1
82#define HIDP_BLUETOOTH_VENDOR_ID 9
83
84struct hidp_connadd_req {
85 int ctrl_sock; // Connected control socket
86 int intr_sock; // Connteted interrupt socket
87 __u16 parser;
88 __u16 rd_size;
89 __u8 *rd_data;
90 __u8 country;
91 __u8 subclass;
92 __u16 vendor;
93 __u16 product;
94 __u16 version;
95 __u32 flags;
96 __u32 idle_to;
97 char name[128];
98};
99
100struct hidp_conndel_req {
101 bdaddr_t bdaddr;
102 __u32 flags;
103};
104
105struct hidp_conninfo {
106 bdaddr_t bdaddr;
107 __u32 flags;
108 __u16 state;
109 __u16 vendor;
110 __u16 product;
111 __u16 version;
112 char name[128];
113};
114
115struct hidp_connlist_req {
116 __u32 cnum;
117 struct hidp_conninfo __user *ci;
118};
119
120int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, struct socket *intr_sock);
121int hidp_del_connection(struct hidp_conndel_req *req);
122int hidp_get_connlist(struct hidp_connlist_req *req);
123int hidp_get_conninfo(struct hidp_conninfo *ci);
124
125/* HIDP session defines */
126struct hidp_session {
127 struct list_head list;
128
129 struct socket *ctrl_sock;
130 struct socket *intr_sock;
131
132 bdaddr_t bdaddr;
133
134 unsigned long state;
135 unsigned long flags;
136 unsigned long idle_to;
137
138 uint ctrl_mtu;
139 uint intr_mtu;
140
141 atomic_t terminate;
142
143 unsigned char keys[8];
144 unsigned char leds;
145
146 struct input_dev *input;
147
148 struct timer_list timer;
149
150 struct sk_buff_head ctrl_transmit;
151 struct sk_buff_head intr_transmit;
152};
153
154static inline void hidp_schedule(struct hidp_session *session)
155{
156 struct sock *ctrl_sk = session->ctrl_sock->sk;
157 struct sock *intr_sk = session->intr_sock->sk;
158
159 wake_up_interruptible(ctrl_sk->sk_sleep);
160 wake_up_interruptible(intr_sk->sk_sleep);
161}
162
163/* HIDP init defines */
164extern int __init hidp_init_sockets(void);
165extern void __exit hidp_cleanup_sockets(void);
166
167#endif /* __HIDP_H */
diff --git a/net/bluetooth/hidp/sock.c b/net/bluetooth/hidp/sock.c
new file mode 100644
index 000000000000..fabb36d4666b
--- /dev/null
+++ b/net/bluetooth/hidp/sock.c
@@ -0,0 +1,232 @@
1/*
2 HIDP implementation for Linux Bluetooth stack (BlueZ).
3 Copyright (C) 2003-2004 Marcel Holtmann <marcel@holtmann.org>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License version 2 as
7 published by the Free Software Foundation;
8
9 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
10 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
11 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
12 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
13 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
18 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
19 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
20 SOFTWARE IS DISCLAIMED.
21*/
22
23#include <linux/config.h>
24#include <linux/module.h>
25
26#include <linux/types.h>
27#include <linux/errno.h>
28#include <linux/kernel.h>
29#include <linux/major.h>
30#include <linux/sched.h>
31#include <linux/slab.h>
32#include <linux/poll.h>
33#include <linux/fcntl.h>
34#include <linux/skbuff.h>
35#include <linux/socket.h>
36#include <linux/ioctl.h>
37#include <linux/file.h>
38#include <linux/init.h>
39#include <net/sock.h>
40
41#include "hidp.h"
42
43#ifndef CONFIG_BT_HIDP_DEBUG
44#undef BT_DBG
45#define BT_DBG(D...)
46#endif
47
48static int hidp_sock_release(struct socket *sock)
49{
50 struct sock *sk = sock->sk;
51
52 BT_DBG("sock %p sk %p", sock, sk);
53
54 if (!sk)
55 return 0;
56
57 sock_orphan(sk);
58 sock_put(sk);
59
60 return 0;
61}
62
63static int hidp_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
64{
65 void __user *argp = (void __user *) arg;
66 struct hidp_connadd_req ca;
67 struct hidp_conndel_req cd;
68 struct hidp_connlist_req cl;
69 struct hidp_conninfo ci;
70 struct socket *csock;
71 struct socket *isock;
72 int err;
73
74 BT_DBG("cmd %x arg %lx", cmd, arg);
75
76 switch (cmd) {
77 case HIDPCONNADD:
78 if (!capable(CAP_NET_ADMIN))
79 return -EACCES;
80
81 if (copy_from_user(&ca, argp, sizeof(ca)))
82 return -EFAULT;
83
84 csock = sockfd_lookup(ca.ctrl_sock, &err);
85 if (!csock)
86 return err;
87
88 isock = sockfd_lookup(ca.intr_sock, &err);
89 if (!isock) {
90 fput(csock->file);
91 return err;
92 }
93
94 if (csock->sk->sk_state != BT_CONNECTED || isock->sk->sk_state != BT_CONNECTED) {
95 fput(csock->file);
96 fput(isock->file);
97 return -EBADFD;
98 }
99
100 err = hidp_add_connection(&ca, csock, isock);
101 if (!err) {
102 if (copy_to_user(argp, &ca, sizeof(ca)))
103 err = -EFAULT;
104 } else {
105 fput(csock->file);
106 fput(isock->file);
107 }
108
109 return err;
110
111 case HIDPCONNDEL:
112 if (!capable(CAP_NET_ADMIN))
113 return -EACCES;
114
115 if (copy_from_user(&cd, argp, sizeof(cd)))
116 return -EFAULT;
117
118 return hidp_del_connection(&cd);
119
120 case HIDPGETCONNLIST:
121 if (copy_from_user(&cl, argp, sizeof(cl)))
122 return -EFAULT;
123
124 if (cl.cnum <= 0)
125 return -EINVAL;
126
127 err = hidp_get_connlist(&cl);
128 if (!err && copy_to_user(argp, &cl, sizeof(cl)))
129 return -EFAULT;
130
131 return err;
132
133 case HIDPGETCONNINFO:
134 if (copy_from_user(&ci, argp, sizeof(ci)))
135 return -EFAULT;
136
137 err = hidp_get_conninfo(&ci);
138 if (!err && copy_to_user(argp, &ci, sizeof(ci)))
139 return -EFAULT;
140
141 return err;
142 }
143
144 return -EINVAL;
145}
146
147static struct proto_ops hidp_sock_ops = {
148 .family = PF_BLUETOOTH,
149 .owner = THIS_MODULE,
150 .release = hidp_sock_release,
151 .ioctl = hidp_sock_ioctl,
152 .bind = sock_no_bind,
153 .getname = sock_no_getname,
154 .sendmsg = sock_no_sendmsg,
155 .recvmsg = sock_no_recvmsg,
156 .poll = sock_no_poll,
157 .listen = sock_no_listen,
158 .shutdown = sock_no_shutdown,
159 .setsockopt = sock_no_setsockopt,
160 .getsockopt = sock_no_getsockopt,
161 .connect = sock_no_connect,
162 .socketpair = sock_no_socketpair,
163 .accept = sock_no_accept,
164 .mmap = sock_no_mmap
165};
166
167static struct proto hidp_proto = {
168 .name = "HIDP",
169 .owner = THIS_MODULE,
170 .obj_size = sizeof(struct bt_sock)
171};
172
173static int hidp_sock_create(struct socket *sock, int protocol)
174{
175 struct sock *sk;
176
177 BT_DBG("sock %p", sock);
178
179 if (sock->type != SOCK_RAW)
180 return -ESOCKTNOSUPPORT;
181
182 sk = sk_alloc(PF_BLUETOOTH, GFP_KERNEL, &hidp_proto, 1);
183 if (!sk)
184 return -ENOMEM;
185
186 sock_init_data(sock, sk);
187
188 sock->ops = &hidp_sock_ops;
189
190 sock->state = SS_UNCONNECTED;
191
192 sock_reset_flag(sk, SOCK_ZAPPED);
193
194 sk->sk_protocol = protocol;
195 sk->sk_state = BT_OPEN;
196
197 return 0;
198}
199
200static struct net_proto_family hidp_sock_family_ops = {
201 .family = PF_BLUETOOTH,
202 .owner = THIS_MODULE,
203 .create = hidp_sock_create
204};
205
206int __init hidp_init_sockets(void)
207{
208 int err;
209
210 err = proto_register(&hidp_proto, 0);
211 if (err < 0)
212 return err;
213
214 err = bt_sock_register(BTPROTO_HIDP, &hidp_sock_family_ops);
215 if (err < 0)
216 goto error;
217
218 return 0;
219
220error:
221 BT_ERR("Can't register HIDP socket");
222 proto_unregister(&hidp_proto);
223 return err;
224}
225
226void __exit hidp_cleanup_sockets(void)
227{
228 if (bt_sock_unregister(BTPROTO_HIDP) < 0)
229 BT_ERR("Can't unregister HIDP socket");
230
231 proto_unregister(&hidp_proto);
232}