📄 core.c
字号:
default: __hidp_send_ctrl_message(session, HIDP_TRANS_HANDSHAKE | HIDP_HSHK_ERR_UNSUPPORTED_REQUEST, NULL, 0); break; } kfree_skb(skb);}static inline void hidp_recv_intr_frame(struct hidp_session *session, struct sk_buff *skb){ unsigned char hdr; BT_DBG("session %p skb %p len %d", session, skb, skb->len); hdr = skb->data[0]; skb_pull(skb, 1); if (hdr == (HIDP_TRANS_DATA | HIDP_DATA_RTYPE_INPUT)) { hidp_set_timer(session); if (session->input) hidp_input_report(session, skb); } else { BT_DBG("Unsupported protocol header 0x%02x", hdr); } kfree_skb(skb);}static int hidp_send_frame(struct socket *sock, unsigned char *data, int len){ struct kvec iv = { data, len }; struct msghdr msg; BT_DBG("sock %p data %p len %d", sock, data, len); if (!len) return 0; memset(&msg, 0, sizeof(msg)); return kernel_sendmsg(sock, &msg, &iv, 1, len);}static void hidp_process_transmit(struct hidp_session *session){ struct sk_buff *skb; BT_DBG("session %p", session); while ((skb = skb_dequeue(&session->ctrl_transmit))) { if (hidp_send_frame(session->ctrl_sock, skb->data, skb->len) < 0) { skb_queue_head(&session->ctrl_transmit, skb); break; } hidp_set_timer(session); kfree_skb(skb); } while ((skb = skb_dequeue(&session->intr_transmit))) { if (hidp_send_frame(session->intr_sock, skb->data, skb->len) < 0) { skb_queue_head(&session->intr_transmit, skb); break; } hidp_set_timer(session); kfree_skb(skb); }}static int hidp_session(void *arg){ struct hidp_session *session = arg; struct sock *ctrl_sk = session->ctrl_sock->sk; struct sock *intr_sk = session->intr_sock->sk; struct sk_buff *skb; int vendor = 0x0000, product = 0x0000; wait_queue_t ctrl_wait, intr_wait; BT_DBG("session %p", session); if (session->input) { vendor = session->input->id.vendor; product = session->input->id.product; } daemonize("khidpd_%04x%04x", vendor, product); set_user_nice(current, -15); current->flags |= PF_NOFREEZE; init_waitqueue_entry(&ctrl_wait, current); init_waitqueue_entry(&intr_wait, current); add_wait_queue(ctrl_sk->sk_sleep, &ctrl_wait); add_wait_queue(intr_sk->sk_sleep, &intr_wait); while (!atomic_read(&session->terminate)) { set_current_state(TASK_INTERRUPTIBLE); if (ctrl_sk->sk_state != BT_CONNECTED || intr_sk->sk_state != BT_CONNECTED) break; while ((skb = skb_dequeue(&ctrl_sk->sk_receive_queue))) { skb_orphan(skb); hidp_recv_ctrl_frame(session, skb); } while ((skb = skb_dequeue(&intr_sk->sk_receive_queue))) { skb_orphan(skb); hidp_recv_intr_frame(session, skb); } hidp_process_transmit(session); schedule(); } set_current_state(TASK_RUNNING); remove_wait_queue(intr_sk->sk_sleep, &intr_wait); remove_wait_queue(ctrl_sk->sk_sleep, &ctrl_wait); down_write(&hidp_session_sem); hidp_del_timer(session); if (intr_sk->sk_state != BT_CONNECTED) wait_event_timeout(*(ctrl_sk->sk_sleep), (ctrl_sk->sk_state == BT_CLOSED), HZ); fput(session->ctrl_sock->file); wait_event_timeout(*(intr_sk->sk_sleep), (intr_sk->sk_state == BT_CLOSED), HZ); fput(session->intr_sock->file); __hidp_unlink_session(session); if (session->input) { input_unregister_device(session->input); session->input = NULL; } up_write(&hidp_session_sem); kfree(session); return 0;}static inline void hidp_setup_input(struct hidp_session *session, struct hidp_connadd_req *req){ struct input_dev *input = session->input; int i; input->private = session; input->name = "Bluetooth HID Boot Protocol Device"; input->id.bustype = BUS_BLUETOOTH; input->id.vendor = req->vendor; input->id.product = req->product; input->id.version = req->version; if (req->subclass & 0x40) { set_bit(EV_KEY, input->evbit); set_bit(EV_LED, input->evbit); set_bit(EV_REP, input->evbit); set_bit(LED_NUML, input->ledbit); set_bit(LED_CAPSL, input->ledbit); set_bit(LED_SCROLLL, input->ledbit); set_bit(LED_COMPOSE, input->ledbit); set_bit(LED_KANA, input->ledbit); for (i = 0; i < sizeof(hidp_keycode); i++) set_bit(hidp_keycode[i], input->keybit); clear_bit(0, input->keybit); } if (req->subclass & 0x80) { input->evbit[0] = BIT(EV_KEY) | BIT(EV_REL); input->keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE); input->relbit[0] = BIT(REL_X) | BIT(REL_Y); input->keybit[LONG(BTN_MOUSE)] |= BIT(BTN_SIDE) | BIT(BTN_EXTRA); input->relbit[0] |= BIT(REL_WHEEL); } input->event = hidp_input_event; input_register_device(input);}int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, struct socket *intr_sock){ struct hidp_session *session, *s; int err; BT_DBG(""); if (bacmp(&bt_sk(ctrl_sock->sk)->src, &bt_sk(intr_sock->sk)->src) || bacmp(&bt_sk(ctrl_sock->sk)->dst, &bt_sk(intr_sock->sk)->dst)) return -ENOTUNIQ; session = kmalloc(sizeof(struct hidp_session), GFP_KERNEL); if (!session) return -ENOMEM; memset(session, 0, sizeof(struct hidp_session)); session->input = input_allocate_device(); if (!session->input) { kfree(session); return -ENOMEM; } down_write(&hidp_session_sem); s = __hidp_get_session(&bt_sk(ctrl_sock->sk)->dst); if (s && s->state == BT_CONNECTED) { err = -EEXIST; goto failed; } bacpy(&session->bdaddr, &bt_sk(ctrl_sock->sk)->dst); session->ctrl_mtu = min_t(uint, l2cap_pi(ctrl_sock->sk)->omtu, l2cap_pi(ctrl_sock->sk)->imtu); session->intr_mtu = min_t(uint, l2cap_pi(intr_sock->sk)->omtu, l2cap_pi(intr_sock->sk)->imtu); BT_DBG("ctrl mtu %d intr mtu %d", session->ctrl_mtu, session->intr_mtu); session->ctrl_sock = ctrl_sock; session->intr_sock = intr_sock; session->state = BT_CONNECTED; init_timer(&session->timer); session->timer.function = hidp_idle_timeout; session->timer.data = (unsigned long) session; skb_queue_head_init(&session->ctrl_transmit); skb_queue_head_init(&session->intr_transmit); session->flags = req->flags & (1 << HIDP_BLUETOOTH_VENDOR_ID); session->idle_to = req->idle_to; if (session->input) hidp_setup_input(session, req); __hidp_link_session(session); hidp_set_timer(session); err = kernel_thread(hidp_session, session, CLONE_KERNEL); if (err < 0) goto unlink; if (session->input) { hidp_send_ctrl_message(session, HIDP_TRANS_SET_PROTOCOL | HIDP_PROTO_BOOT, NULL, 0); session->flags |= (1 << HIDP_BOOT_PROTOCOL_MODE); session->leds = 0xff; hidp_input_event(session->input, EV_LED, 0, 0); } up_write(&hidp_session_sem); return 0;unlink: hidp_del_timer(session); __hidp_unlink_session(session); if (session->input) { input_unregister_device(session->input); session->input = NULL; /* don't try to free it here */ }failed: up_write(&hidp_session_sem); kfree(session->input); kfree(session); return err;}int hidp_del_connection(struct hidp_conndel_req *req){ struct hidp_session *session; int err = 0; BT_DBG(""); down_read(&hidp_session_sem); session = __hidp_get_session(&req->bdaddr); if (session) { if (req->flags & (1 << HIDP_VIRTUAL_CABLE_UNPLUG)) { hidp_send_ctrl_message(session, HIDP_TRANS_HID_CONTROL | HIDP_CTRL_VIRTUAL_CABLE_UNPLUG, NULL, 0); } else { /* Flush the transmit queues */ skb_queue_purge(&session->ctrl_transmit); skb_queue_purge(&session->intr_transmit); /* Kill session thread */ atomic_inc(&session->terminate); hidp_schedule(session); } } else err = -ENOENT; up_read(&hidp_session_sem); return err;}int hidp_get_connlist(struct hidp_connlist_req *req){ struct list_head *p; int err = 0, n = 0; BT_DBG(""); down_read(&hidp_session_sem); list_for_each(p, &hidp_session_list) { struct hidp_session *session; struct hidp_conninfo ci; session = list_entry(p, struct hidp_session, list); __hidp_copy_session(session, &ci); if (copy_to_user(req->ci, &ci, sizeof(ci))) { err = -EFAULT; break; } if (++n >= req->cnum) break; req->ci++; } req->cnum = n; up_read(&hidp_session_sem); return err;}int hidp_get_conninfo(struct hidp_conninfo *ci){ struct hidp_session *session; int err = 0; down_read(&hidp_session_sem); session = __hidp_get_session(&ci->bdaddr); if (session) __hidp_copy_session(session, ci); else err = -ENOENT; up_read(&hidp_session_sem); return err;}static int __init hidp_init(void){ l2cap_load(); BT_INFO("HIDP (Human Interface Emulation) ver %s", VERSION); return hidp_init_sockets();}static void __exit hidp_exit(void){ hidp_cleanup_sockets();}module_init(hidp_init);module_exit(hidp_exit);MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");MODULE_DESCRIPTION("Bluetooth HIDP ver " VERSION);MODULE_VERSION(VERSION);MODULE_LICENSE("GPL");MODULE_ALIAS("bt-proto-6");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -