📄 core.c
字号:
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; } if (session->hid) { vendor = session->hid->vendor; product = session->hid->product; } daemonize("khidpd_%04x%04x", vendor, product); set_user_nice(current, -15); 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 (session->input) { input_unregister_device(session->input); session->input = NULL; } if (session->hid) { if (session->hid->claimed & HID_CLAIMED_INPUT) hidinput_disconnect(session->hid); hid_free_device(session->hid); } fput(session->intr_sock->file); wait_event_timeout(*(ctrl_sk->sk_sleep), (ctrl_sk->sk_state == BT_CLOSED), msecs_to_jiffies(500)); fput(session->ctrl_sock->file); __hidp_unlink_session(session); up_write(&hidp_session_sem); kfree(session); return 0;}static struct device *hidp_get_device(struct hidp_session *session){ bdaddr_t *src = &bt_sk(session->ctrl_sock->sk)->src; bdaddr_t *dst = &bt_sk(session->ctrl_sock->sk)->dst; struct hci_dev *hdev; struct hci_conn *conn; hdev = hci_get_route(dst, src); if (!hdev) return NULL; conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst); hci_dev_put(hdev); return conn ? &conn->dev : NULL;}static inline int hidp_setup_input(struct hidp_session *session, struct hidp_connadd_req *req){ struct input_dev *input = session->input; int i; input_set_drvdata(input, 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_MASK(EV_KEY) | BIT_MASK(EV_REL); input->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_RIGHT) | BIT_MASK(BTN_MIDDLE); input->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y); input->keybit[BIT_WORD(BTN_MOUSE)] |= BIT_MASK(BTN_SIDE) | BIT_MASK(BTN_EXTRA); input->relbit[0] |= BIT_MASK(REL_WHEEL); } input->dev.parent = hidp_get_device(session); input->event = hidp_input_event; return input_register_device(input);}static int hidp_open(struct hid_device *hid){ return 0;}static void hidp_close(struct hid_device *hid){}static const struct { __u16 idVendor; __u16 idProduct; unsigned quirks;} hidp_blacklist[] = { /* Apple wireless Mighty Mouse */ { 0x05ac, 0x030c, HID_QUIRK_MIGHTYMOUSE | HID_QUIRK_INVERT_HWHEEL }, { } /* Terminating entry */};static void hidp_setup_quirks(struct hid_device *hid){ unsigned int n; for (n = 0; hidp_blacklist[n].idVendor; n++) if (hidp_blacklist[n].idVendor == le16_to_cpu(hid->vendor) && hidp_blacklist[n].idProduct == le16_to_cpu(hid->product)) hid->quirks = hidp_blacklist[n].quirks;}static inline void hidp_setup_hid(struct hidp_session *session, struct hidp_connadd_req *req){ struct hid_device *hid = session->hid; struct hid_report *report; bdaddr_t src, dst; baswap(&src, &bt_sk(session->ctrl_sock->sk)->src); baswap(&dst, &bt_sk(session->ctrl_sock->sk)->dst); hid->driver_data = session; hid->country = req->country; hid->bus = BUS_BLUETOOTH; hid->vendor = req->vendor; hid->product = req->product; hid->version = req->version; strncpy(hid->name, req->name, 128); strncpy(hid->phys, batostr(&src), 64); strncpy(hid->uniq, batostr(&dst), 64); hid->dev = hidp_get_device(session); hid->hid_open = hidp_open; hid->hid_close = hidp_close; hid->hidinput_input_event = hidp_hidinput_event; hidp_setup_quirks(hid); list_for_each_entry(report, &hid->report_enum[HID_INPUT_REPORT].report_list, list) hidp_send_report(session, report); list_for_each_entry(report, &hid->report_enum[HID_FEATURE_REPORT].report_list, list) hidp_send_report(session, report); if (hidinput_connect(hid) == 0) hid->claimed |= HID_CLAIMED_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 = kzalloc(sizeof(struct hidp_session), GFP_KERNEL); if (!session) return -ENOMEM; BT_DBG("rd_data %p rd_size %d", req->rd_data, req->rd_size); if (req->rd_size > 0) { unsigned char *buf = kmalloc(req->rd_size, GFP_KERNEL); if (!buf) { kfree(session); return -ENOMEM; } if (copy_from_user(buf, req->rd_data, req->rd_size)) { kfree(buf); kfree(session); return -EFAULT; } session->hid = hid_parse_report(buf, req->rd_size); kfree(buf); if (!session->hid) { kfree(session); return -EINVAL; } } if (!session->hid) { 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) { err = hidp_setup_input(session, req); if (err < 0) goto failed; } if (session->hid) hidp_setup_hid(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); if (session->hid) hid_free_device(session->hid); input_free_device(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 + -