/* * return appropriate mode for HID descriptor */ const char * hid_mode(prop_data_t desc) { report_desc_t r; hid_data_t d; struct hid_item h; const char *mode; hid_init(NULL); mode = BTDEVauth; /* default */ r = hid_use_report_desc(prop_data_data_nocopy(desc), prop_data_size(desc)); if (r == NULL) err(EXIT_FAILURE, "hid_use_report_desc"); d = hid_start_parse(r, ~0, -1); while (hid_get_item(d, &h) > 0) { if (h.kind == hid_collection && HID_PAGE(h.usage) == HUP_GENERIC_DESKTOP && HID_USAGE(h.usage) == HUG_KEYBOARD) mode = BTDEVencrypt; } hid_end_parse(d); hid_dispose_report_desc(r); return mode; }
report_desc_t hid_get_report_desc(int fd) { struct usb_gen_descriptor ugd; report_desc_t rep; void *data; memset(&ugd, 0, sizeof(ugd)); /* get actual length first */ ugd.ugd_data = hid_pass_ptr(NULL); ugd.ugd_maxlen = 65535; if (ioctl(fd, USB_GET_REPORT_DESC, &ugd) < 0) { #ifdef HID_COMPAT7 /* could not read descriptor */ /* try FreeBSD 7 compat code */ return (hid_get_report_desc_compat7(fd)); #else return (NULL); #endif } /* * NOTE: The kernel will return a failure if * "ugd_actlen" is zero. */ data = malloc(ugd.ugd_actlen); if (data == NULL) return (NULL); /* fetch actual descriptor */ ugd.ugd_data = hid_pass_ptr(data); ugd.ugd_maxlen = ugd.ugd_actlen; if (ioctl(fd, USB_GET_REPORT_DESC, &ugd) < 0) { /* could not read descriptor */ free(data); return (NULL); } /* sanity check */ if (ugd.ugd_actlen < 1) { /* invalid report descriptor */ free(data); return (NULL); } /* check END_COLLECTION */ if (((unsigned char *)data)[ugd.ugd_actlen -1] != 0xC0) { /* invalid end byte */ free(data); return (NULL); } rep = hid_use_report_desc(data, ugd.ugd_actlen); free(data); return (rep); }
report_desc_t hid_get_report_desc_compat7(int fd) { struct usb_ctl_report_desc rep; rep.ucrd_size = 0; if (ioctl(fd, USB_GET_REPORT_DESC, &rep) < 0) return (NULL); return (hid_use_report_desc(rep.ucrd_data, (unsigned int)rep.ucrd_size)); }
static int32_t hid_sdp_query(bdaddr_t const *local, struct hid_device *hd, int32_t *error) { void *ss = NULL; uint8_t *hid_descriptor = NULL; int32_t i, control_psm = -1, interrupt_psm = -1, reconnect_initiate = -1, normally_connectable = 0, battery_power = 0, hid_descriptor_length = -1; if (local == NULL) local = NG_HCI_BDADDR_ANY; if (hd == NULL) hid_sdp_query_exit(EINVAL); for (i = 0; i < nvalues; i ++) { values[i].flags = SDP_ATTR_INVALID; values[i].attr = 0; values[i].vlen = sizeof(buffer[i]); values[i].value = buffer[i]; } if ((ss = sdp_open(local, &hd->bdaddr)) == NULL) hid_sdp_query_exit(ENOMEM); if (sdp_error(ss) != 0) hid_sdp_query_exit(sdp_error(ss)); if (sdp_search(ss, 1, &service, nattrs, attrs, nvalues, values) != 0) hid_sdp_query_exit(sdp_error(ss)); sdp_close(ss); ss = NULL; for (i = 0; i < nvalues; i ++) { if (values[i].flags != SDP_ATTR_OK) continue; switch (values[i].attr) { case SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST: control_psm = hid_sdp_parse_protocol_descriptor_list(&values[i]); break; case SDP_ATTR_ADDITIONAL_PROTOCOL_DESCRIPTOR_LISTS: interrupt_psm = hid_sdp_parse_protocol_descriptor_list(&values[i]); break; case 0x0205: /* HIDReconnectInitiate */ reconnect_initiate = hid_sdp_parse_boolean(&values[i]); break; case 0x0206: /* HIDDescriptorList */ if (hid_sdp_parse_hid_descriptor(&values[i]) == 0) { hid_descriptor = values[i].value; hid_descriptor_length = values[i].vlen; } break; case 0x0209: /* HIDBatteryPower */ battery_power = hid_sdp_parse_boolean(&values[i]); break; case 0x020d: /* HIDNormallyConnectable */ normally_connectable = hid_sdp_parse_boolean(&values[i]); break; } } if (control_psm == -1 || interrupt_psm == -1 || reconnect_initiate == -1 || hid_descriptor == NULL || hid_descriptor_length == -1) hid_sdp_query_exit(ENOATTR); hd->control_psm = control_psm; hd->interrupt_psm = interrupt_psm; hd->reconnect_initiate = reconnect_initiate? 1 : 0; hd->battery_power = battery_power? 1 : 0; hd->normally_connectable = normally_connectable? 1 : 0; hd->desc = hid_use_report_desc(hid_descriptor, hid_descriptor_length); if (hd->desc == NULL) hid_sdp_query_exit(ENOMEM); return (0); }